Spring注解开发
今天,学习给容器中注入组件,昨天,我们学习了条件注解,可以在满足一定的条件下,注入bean,今天的@Import注解也能帮我们完成相同的功能。
@Import注解
给容器中注册组件主要有以下三种方法 :
1)、包扫描+组件标记注解(@Controller、@Service、@Repository、@Component)[导入我们自己写的组件]
2)、@Bean[导入第三方包里面的组件]
3)、@Import[快速给容器中导入一个组件]
@Bean导入,只能一个一个的导入,不太方便,所以需要@Import注解。现在我们来看@Import的用法。
一、@Import
@Import:容器会自动注册加了该注解的组件,组件的id默认是组件的全类名
1)在com.liuzhuo.bean包下,创建Color对象。
2)修改配置类MainConfig2类:(看@Import注解)
//配置类==配置文件
@Configuration //告诉spring这是一个配置类,用来生成bean
@Import(Color.class)
public class MainConfig2
3)在test类中,创建新的测试方法:
@Test
public void testImport() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
printBeanName(applicationContext);
}
private void printBeanName(AnnotationConfigApplicationContext applicationContext) {
String[] names = applicationContext.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
4) 运行测试方法:
mainConfig2
com.liuzhuo.bean.Color
person
bier
观察结果:发现Color组件已经注册到容器中了,而且id名是全类名。
点击@Import。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
Class<?>[] value();
}
发现,@Import中的value是一个Class类型的数组,说明可以注入多个Class类型
1)现在,在com.liuzhuo.bean包下,再创建一个Red类:
public class Red {
}
2)修改配置类MainConfig2:
//配置类==配置文件
@Configuration //告诉spring这是一个配置类,用来生成bean
@Import({Color.class, Red.class})
public class MainConfig2
3) 运行测试方法testImport:
mainConfig2
com.liuzhuo.bean.Color
com.liuzhuo.bean.Red
person
bier
结果:Red类也被注册到容器中了。
二、ImportSelect
ImportSelect:返回要导入的全类名数组。
在@Import的value属性中,导入实现了ImportSelect接口的类,该实现类返回我们需要导入的组件的全类名即可。
1)在com.liuzhuo.condition包下,创建MyImportSelect类并实现ImportSelect接口:
public class MyImportSelect implements ImportSelector {
/*
* annotationMetadata:获取注解的信息。
* 返回值:全类名的字符串数组
* */
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//返回值不能是null,否则会出空指针异常
return new String[0];
}
}
2) 在com.liuzhuo.bean包下,创建Bule、Yellow类。
3)修改selectImports方法是返回值:
public class MyImportSelect implements ImportSelector {
/*
* annotationMetadata:获取注解的信息。
* 返回值:全类名的字符串数组
* */
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//返回值不能是null,否则会出空指针异常
return new String[]{"com.liuzhuo.bean.Blue","com.liuzhuo.bean.Yellow"};
}
}
4) 修改配置类MainConfig2:(添加类MyImportSelect类)
//配置类==配置文件
@Configuration //告诉spring这是一个配置类,用来生成bean
@Import({Color.class, Red.class, MyImportSelect.class})
public class MainConfig2
5)运行测试方法testImport:
结果:
mainConfig2
com.liuzhuo.bean.Color
com.liuzhuo.bean.Red
com.liuzhuo.bean.Blue
com.liuzhuo.bean.Yellow
person
bier
发现:Blue、Yellow也被注册到容器中了。
三、ImportBeanDefinitionRegistrar
ImportBeanDefinitionRegistrar :手动注册Bean。
使用的形式与ImportSelect类似。
1)在com.liuzhuo.condition包下,创建MyImportBeanDefinitionRegistrar类实现ImportBeanDefinitionRegistrar接口。
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/*
*
* importingClassMetadata:注解类的信息
* registry:注册组件,使用register.registerBeanDefinition()方法,手动注册Bean。
* */
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
}
}
2)在com.liuzhuo.bean包下,创建RainBow类。
public class RainBow {
}
3) 修改registerBeanDefinitions方法:
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
/*
* 这里,我们根据是否有Bule和Yellow组件来注册RainBow组件。
* */
//注意这里传入的是Bean的id。
boolean b = registry.containsBeanDefinition("com.liuzhuo.bean.Blue");
boolean y = registry.containsBeanDefinition("com.liuzhuo.bean.Yellow");
if (b && y) {
//两个参数:String beanName
// BeanDefinition beanDefinition
// beanName:要注册的Bean的id
//beanDefinition:Bean的定义。是一个接口,我们需要传入一个实现类。
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(RainBow.class);
registry.registerBeanDefinition("rainBow", rootBeanDefinition);
}
}
4) 修改配置类MainConfig2:(MyImportBeanDefinitionRegistrar.class)
//配置类==配置文件
@Configuration //告诉spring这是一个配置类,用来生成bean
@Import({Color.class, Red.class, MyImportSelect.class, MyImportBeanDefinitionRegistrar.class})
public class MainConfig2
5) 运行测试方法testImport:
mainConfig2
com.liuzhuo.bean.Color
com.liuzhuo.bean.Red
com.liuzhuo.bean.Blue
com.liuzhuo.bean.Yellow
person
bier
rainBow
结果:发现rainBow已经被注册到容器中了。
FactoryBean
第四种方法给容器注册Bean.
使用Spring提供的FactoryBean(工厂Bean)
1)默认获取的是工厂bean调用getObject创建的对象
2)要想获取工厂Bean本身,需要给id前面加一个&
1) 在com.liuzhuo.bean包下,创建ColorFactoryBean类,实现FactoryBean接口:
public class ColorFactoryBean implements FactoryBean<Color> {
//返回的Bean对象
@Override
public Color getObject() throws Exception {
return new Color();
}
//Bean的类型
@Override
public Class<?> getObjectType() {
return Color.class;
}
//是否是单例:
//true:单例
//false:多例
@Override
public boolean isSingleton() {
return true;
}
}
2) 注册ColorFactoryBean到容器中,在配置文件MainConfig2中:
@Bean
public ColorFactoryBean colorFactoryBean() {
return new ColorFactoryBean();
}
3) 修改testImport方法:
@Test
public void testImport() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
printBeanName(applicationContext);
Object colorFactoryBean = applicationContext.getBean("colorFactoryBean");
System.out.println(colorFactoryBean);
}
4) 结果:
mainConfig2
com.liuzhuo.bean.Color
com.liuzhuo.bean.Red
com.liuzhuo.bean.Blue
com.liuzhuo.bean.Yellow
person
bier
colorFactoryBean
rainBow
com.liuzhuo.bean.Color@6107227e
发现:com.liuzhuo.bean.Color@6107227e 已经注册到容器中了。
注意:我们注册到容器中的是ColorFactoryBean,但是获取Bean的时候,却是Color。底层是调用ColorFactoryBean的getObject()来获取的。
如果就是想要获取ColorFactoryBean本身的话,在id前面加一个&:
Object colorFactoryBean = applicationContext.getBean("colorFactoryBean");
System.out.println(colorFactoryBean);
Object colorFactoryBean2 = applicationContext.getBean("&colorFactoryBean");
System.out.println(colorFactoryBean2);
结果:
com.liuzhuo.bean.Color@6107227e
com.liuzhuo.bean.ColorFactoryBean@7c417213
ps:点击BeanFactory:
会发现有一个字段:String FACTORY_BEAN_PREFIX = "&";
这就是为啥加&会获取FactoryBean本身的原因.