1、包扫描+组件标注注解
使用到的注解如下,主要针对自己写的类
- @Controller
- @Service
- @Repository
- @Component
- @ComponentScan
参考 spring注解开发:ComponentScan组件扫描
2、使用bean注解
主要使用场景:导入第三方包里面的组件,使用到的注解:
- @Bean
参考:spring注解开发:Configuration&Bean
3、使用@Import注解
- 使用方式:@Import(要导入到容器中的组件);容器中就会自动注册这个组件
- bean的id默认是全类名
- 示例:@Import(value = {Person.class})
实战
1、新建一个maven工程,添加如下依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.5.RELEASE</version> </dependency>
2、新建一个实体 Person
package com.yefengyu.annotation.bean; public class Person { private String name; private Integer age; public Person() { } public Person(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
3、新建一个配置类(重点)
package com.yefengyu.annotation.config; import com.yefengyu.annotation.bean.Person; import org.springframework.context.annotation.*; @Configuration @Import(Person.class) public class MainConfig { }
4、测试代码
public static void main(String[] args) { ApplicationContext ctx= new AnnotationConfigApplicationContext(MainConfig.class); String[] names = ctx.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } Person person1= (Person)ctx.getBean(Person.class); //bean的id默认是全类名 Person person2= (Person)ctx.getBean("com.yefengyu.annotation.bean.Person"); }
4、使用ImportSelector
ImportSelector和Import一起使用:首先编写一个类实现ImportSelector接口MyImportSelector,然后将MyImportSelector添加到Import中,那么MyImportSelector自定义逻辑返回需要导入的组件就会被加入到容器中。
利用上面第三节的代码,我们重新添加一个类,这个类什么都没有,现在我们尝试着使用ImportSelector方式将其注册到容器中。
package com.yefengyu.annotation.bean; public class Car { }
1、编写MyImportSelector实现ImportSelector接口,重写selectImports方法,返回的数组中每个字符串就是要导入到容器的组件的全类名。
package com.yefengyu.annotation; import org.springframework.context.annotation.ImportSelector; import org.springframework.core.type.AnnotationMetadata; //自定义逻辑返回需要导入的组件 public class MyImportSelector implements ImportSelector { //返回值就是要导入到容器的组件的全类名 @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { return new String[]{"com.yefengyu.annotation.bean.Car"}; } }
2、修改MainConfig配置类,使用Import注解加入MyImportSelector类,注意下面红色部分。
package com.yefengyu.annotation.config; import com.yefengyu.annotation.MyImportSelector; import com.yefengyu.annotation.bean.Person; import org.springframework.context.annotation.*; @Configuration @Import({Person.class, MyImportSelector.class}) public class MainConfig { }
3、测试,同样使用上面的测试代码,可以看出打印结果为:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
com.yefengyu.annotation.bean.Person
com.yefengyu.annotation.bean.Car
4、针对于public String[] selectImports(AnnotationMetadata annotationMetadata)方法中的参数AnnotationMetadata有很多信息可以帮助筛选要注册的组件。
5、使用ImportBeanDefinitionRegistrar
和使用ImportSelector方式一样,定义一个类实现ImportBeanDefinitionRegistrar接口,重写其中的方法,手动注册组件。
1、定一个类,作为要注册的组件
package com.yefengyu.annotation.bean; public class Alarm { }
2、实现ImportBeanDefinitionRegistrar接口,手动注册组件
package com.yefengyu.annotation; import com.yefengyu.annotation.bean.Alarm; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.type.AnnotationMetadata; public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) { beanDefinitionRegistry.registerBeanDefinition("alarm",new RootBeanDefinition(Alarm.class)); } }
beanDefinitionRegistry.registerBeanDefinition("alarm",new RootBeanDefinition(Alarm.class));
第一个参数是组件名称。
第二个参数是要注册的组件的类型的定义。
AnnotationMetadata 和上一节类似。BeanDefinitionRegistry 的功能很多:
3、修改MainConfig配置类,使用Import注解加入MyImportBeanDefinitionRegistrar类,注意下面红色部分。
package com.yefengyu.annotation.config; import com.yefengyu.annotation.MyImportBeanDefinitionRegistrar; import com.yefengyu.annotation.MyImportSelector; import com.yefengyu.annotation.bean.Person; import org.springframework.context.annotation.*; @Configuration @Import({Person.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class}) public class MainConfig { }
4、测试,同样使用上面的测试代码,可以看出打印结果为:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
com.yefengyu.annotation.bean.Person
com.yefengyu.annotation.bean.Car
alarm
6、使用FactoryBean
1、首先创建一个待加入到容器的组件
package com.yefengyu.annotation.bean; public class Event { }
2、创建一个Spring定义的FactoryBean
package com.yefengyu.annotation; import com.yefengyu.annotation.bean.Event; import org.springframework.beans.factory.FactoryBean; //创建一个Spring定义的FactoryBean public class EventFactoryBean implements FactoryBean<Event> { //返回一个Event对象,这个对象会添加到容器中 @Override public Event getObject() throws Exception { return new Event(); } @Override public Class<?> getObjectType() { return Event.class; } //是单例? //true:这个bean是单实例,在容器中保存一份 //false:多实例,每次获取都会创建一个新的bean; @Override public boolean isSingleton() { return true; } }
3、修改配置类,注意下面bean注解下面的代码
package com.yefengyu.annotation.config; import com.yefengyu.annotation.EventFactoryBean; import com.yefengyu.annotation.MyImportBeanDefinitionRegistrar; import com.yefengyu.annotation.MyImportSelector; import com.yefengyu.annotation.bean.Person; import org.springframework.context.annotation.*; @Configuration @Import({Person.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class}) public class MainConfig { @Bean public EventFactoryBean eventFactoryBean() { return new EventFactoryBean(); } }
4、修改测试代码如下:
package com.yefengyu.annotation; import com.yefengyu.annotation.bean.Person; import com.yefengyu.annotation.config.MainConfig; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Main { public static void main(String[] args) { ApplicationContext ctx= new AnnotationConfigApplicationContext(MainConfig.class); String[] names = ctx.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } //测试EventFactoryBean Object eventFactoryBean = ctx.getBean("eventFactoryBean"); System.out.println("bean 的类型为:" + eventFactoryBean.getClass()); Object factoryBean = ctx.getBean("&eventFactoryBean"); System.out.println("bean 的类型为:" + factoryBean.getClass()); } }
5、结果如下:
mainConfig com.yefengyu.annotation.bean.Person com.yefengyu.annotation.bean.Car eventFactoryBean alarm bean 的类型为:class com.yefengyu.annotation.bean.Event bean 的类型为:class com.yefengyu.annotation.EventFactoryBean
总结:
- 默认获取到的是工厂bean调用getObject创建的对象
ctx.getBean("eventFactoryBean");
- 要获取工厂Bean本身,我们需要给id前面加一个&
ctx.getBean("&eventFactoryBean");