1. 包扫描+组件标注注解
@ComponentScan+ @Controller + @Service + @Repository
2. @Bean注解导入
导入第三方包里的组件
3. @Import快速导入
几个实体类的声明:
package com.niewj.bean;
public class PojoBean {
public PojoBean() {
System.out.println("PojoBean[无注解java类] 初始化~~~");
}
}
package com.niewj.bean;
public class PojoBean2 {
public PojoBean2(){
System.out.println("PojoBean2[无注解java类] 初始化~~~");
}
}
package com.niewj.bean;
public class PojoBean3 {
public PojoBean3(){
System.out.println("PojoBean3[无注解java类] 初始化~~~");
}
}
package com.niewj.bean;
public class Pojo4 {
public Pojo4(){
System.out.println("Pojo4[无注解java类] 初始化~~~");
}
}
package com.niewj.bean;
public class Pojo5 {
public Pojo5(){
System.out.println("Pojo5[无注解java类] 初始化~~~");
}
}
(1) @Import导入单个
package com.niewj.config;
import com.niewj.bean.PojoBean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import(PojoBean.class) // 这里
public class ImportTestConfig {
}
private AnnotationConfigApplicationContext printAnnoBeans(Class clazz) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(clazz);
Arrays.stream(ctx.getBeanDefinitionNames()).forEach(System.out::println);
return ctx;
}
@Test
public void testImport(){
// PojoBean*.java并无注解类, 但是会初始化归入spring容器管理! -> @Import的作用!
ApplicationContext ctx = printAnnoBeans(ImportTestConfig.class);
}
output:
PojoBean[无注解java类] 初始化~~~
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
importTestConfig
com.niewj.bean.PojoBean
可以看到 PojoBean 的初始化和bean id的展示!
(2) @Import导入多个(数组)
普通Javabean并没有任何注解的:
package com.niewj.config;
import com.niewj.bean.PojoBean;
import com.niewj.bean.PojoBean2;
import com.niewj.bean.PojoBean3;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
//@Import(PojoBean.class)
@Import({PojoBean.class, PojoBean2.class, PojoBean3.class}) // 这里
public class ImportTestConfig {
}
测试:
private AnnotationConfigApplicationContext printAnnoBeans(Class clazz) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(clazz);
Arrays.stream(ctx.getBeanDefinitionNames()).forEach(System.out::println);
return ctx;
}
@Test
public void testImport(){
// PojoBean*.java并无注解类, 但是会初始化归入spring容器管理! -> @Import的作用!
ApplicationContext ctx = printAnnoBeans(ImportTestConfig.class);
}
output: 可以看到这三个无注解的普通bean也被容器管理和初始化了!
PojoBean[无注解java类] 初始化~~~
PojoBean2[无注解java类] 初始化~~~
PojoBean3[无注解java类] 初始化~~~
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
importTestConfig
com.niewj.bean.PojoBean
com.niewj.bean.PojoBean2
com.niewj.bean.PojoBean3
(3) @ImportSelector接口
@ImportSelector接口的实现类, 可以放入@Import中使用:
@Import是列出所有; @ImportSelector是返回一个 class name的字符串的数组, 可以理解为@Import的简化版(方便使用)
package com.niewj.config;
import com.niewj.bean.PojoBean;
import com.niewj.bean.PojoBean2;
import com.niewj.bean.PojoBean3;
import com.niewj.condition.MyImportSelector;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
//@Import(PojoBean.class)
//@Import({PojoBean.class, PojoBean2.class, PojoBean3.class})
@Import({PojoBean.class, PojoBean2.class, PojoBean3.class, MyImportSelector.class}) // 这里
public class ImportTestConfig {
}
MyImportSelector:
package com.niewj.condition;
import com.niewj.bean.Pojo4;
import com.niewj.bean.Pojo5;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import java.util.ArrayList;
import java.util.List;
public class MyImportSelector implements ImportSelector {
/**
* 返回的数组中的类名, 也会作为加入容器管理的bean
* @param importingClassMetadata 可以获取到当前类的所有注解信息!
* @return
*/
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
List classNameList = new ArrayList<>();
// 可以假设Pojo4/Pojo5的类名都读取字配置文件, 比如 spring.factories-->类似springboot源码
classNameList.add(Pojo4.class.getName());
classNameList.add(Pojo5.class.getName());
return classNameList.toArray(new String[0]);
}
}
testcase:
private AnnotationConfigApplicationContext printAnnoBeans(Class clazz) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(clazz);
Arrays.stream(ctx.getBeanDefinitionNames()).forEach(System.out::println);
return ctx;
}
@Test
public void testImport(){
// PojoBean*.java并无注解类, 但是会初始化归入spring容器管理! -> @Import的作用!
ApplicationContext ctx = printAnnoBeans(ImportTestConfig.class);
}
output: 可见: PojoBean/PojoBean2/PojoBean3都初始化了; 而且 ImportSelector中加入数组的 Pojo4/Pojo5也初始化了!
PojoBean[无注解java类] 初始化~~~
PojoBean2[无注解java类] 初始化~~~
PojoBean3[无注解java类] 初始化~~~
Pojo4[无注解java类] 初始化~~~
Pojo5[无注解java类] 初始化~~~
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
importTestConfig
com.niewj.bean.PojoBean
com.niewj.bean.PojoBean2
com.niewj.bean.PojoBean3
com.niewj.bean.Pojo4
com.niewj.bean.Pojo5
(4). ImportBeanDefinitionRegistrar
可以结合已有beanDefinition信息!
package com.niewj.config;
import com.niewj.bean.PojoBean;
import com.niewj.bean.PojoBean2;
import com.niewj.bean.PojoBean3;
import com.niewj.condition.MyImportBeanDefRegistrar;
import com.niewj.condition.MyImportSelector;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
//@Import(PojoBean.class)
//@Import({PojoBean.class, PojoBean2.class, PojoBean3.class})
@Import({PojoBean.class, PojoBean2.class, PojoBean3.class, MyImportSelector.class, MyImportBeanDefRegistrar.class})
public class ImportTestConfig {
}
MyImportBeanDefRegistrar:
package com.niewj.condition;
import com.niewj.bean.Pojo4;
import com.niewj.bean.Pojo5;
import com.niewj.bean.PojoWhenHasPojo4AndPojo5;
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 MyImportBeanDefRegistrar implements ImportBeanDefinitionRegistrar {
/** 可以获取容器中已有 BeanDefinition 信息来做一些判断;
* 比如, 如果有这两个类, 也加入类 PojoWhenHasPojo4AndPojo5
* @param importingClassMetadata 可以获取到当前类(扫描到的类)的所有注解信息
* @param registry beanDefinition的注册接口
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean hasPojo5 = registry.containsBeanDefinition(Pojo5.class.getName());
boolean hasPojo4 = registry.containsBeanDefinition(Pojo4.class.getName());
if(hasPojo4 && hasPojo5){
RootBeanDefinition beanDefinition = new RootBeanDefinition(PojoWhenHasPojo4AndPojo5.class);
registry.registerBeanDefinition("pojoWhenHasPojo4AndPojo5", beanDefinition);
}
}
}
测试:
private AnnotationConfigApplicationContext printAnnoBeans(Class clazz) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(clazz);
Arrays.stream(ctx.getBeanDefinitionNames()).forEach(System.out::println);
return ctx;
}
@Test
public void testImport(){
// PojoBean*.java并无注解类, 但是会初始化归入spring容器管理! -> @Import的作用!
ApplicationContext ctx = printAnnoBeans(ImportTestConfig.class);
}
output: 可以看到 PojoWhenHasPojo4AndPojo5 的初始化!
PojoBean[无注解java类] 初始化~~~
PojoBean2[无注解java类] 初始化~~~
PojoBean3[无注解java类] 初始化~~~
Pojo4[无注解java类] 初始化~~~
Pojo5[无注解java类] 初始化~~~
PojoWhenHasPojo4AndPojo5[无注解java类] 初始化~~~
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
importTestConfig
com.niewj.bean.PojoBean
com.niewj.bean.PojoBean2
com.niewj.bean.PojoBean3
com.niewj.bean.Pojo4
com.niewj.bean.Pojo5
pojoWhenHasPojo4AndPojo5
4. Spring的FactoryBean接口(工厂Bean)
- getObject() 获取要生产的对象
- getObjectType() 获取要生产的对象的类型
- isSingleton() 定义是单例还是多例
注意: 通过 ctx.getBean("beanId") 调用, 得到的是 getObject()方法返回的对象的实际内容;
通过ctx.getBean("&beanId")调用, 得到的才是实际的FactoryBean对象
package com.niewj.bean;
public class Pojo7 {
public Pojo7(){
System.out.println("Pojo7[无注解java类] 初始化~~~");
}
}
package com.niewj.bean;
import org.springframework.beans.factory.FactoryBean;
public class Pojo7FactoryBean implements FactoryBean {
@Override
public Pojo7 getObject() throws Exception {
System.out.println("Pojo7FactoryBean---FactoryBean---初始化");
return new Pojo7();
}
@Override
public Class> getObjectType() {
return Pojo7.class;
}
@Override
public boolean isSingleton() {
return false;
}
}
private AnnotationConfigApplicationContext printAnnoBeans(Class clazz) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(clazz);
Arrays.stream(ctx.getBeanDefinitionNames()).forEach(System.out::println);
return ctx;
}
@Test
public void testImport(){
// PojoBean*.java并无注解类, 但是会初始化归入spring容器管理! -> @Import的作用!
ApplicationContext ctx = printAnnoBeans(ImportTestConfig.class);
Pojo7 bean1 = ctx.getBean("pojo7", Pojo7.class);
System.out.println(bean1);
Pojo7FactoryBean bean2 = ctx.getBean("&pojo7", Pojo7FactoryBean.class);
System.out.println(bean2);
}
output: 看最后两行: 说明了 FactoryBean的特征: &beanId得到是 FactoryBean; beanId得到是 getObject()返回的实际Bean!
PojoBean[无注解java类] 初始化~~~
PojoBean2[无注解java类] 初始化~~~
PojoBean3[无注解java类] 初始化~~~
Pojo4[无注解java类] 初始化~~~
Pojo5[无注解java类] 初始化~~~
PojoWhenHasPojo4AndPojo5[无注解java类] 初始化~~~
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
importTestConfig
com.niewj.bean.PojoBean
com.niewj.bean.PojoBean2
com.niewj.bean.PojoBean3
com.niewj.bean.Pojo4
com.niewj.bean.Pojo5
pojo7
pojoWhenHasPojo4AndPojo5
Pojo7FactoryBean---FactoryBean---初始化
Pojo7[无注解java类] 初始化~~~
com.niewj.bean.Pojo7@2bbf180e
com.niewj.bean.Pojo7FactoryBean@163e4e87
小结
向spring容器中注册组件有四种方式:
- @ComponentScan+注解 @Controller/@Service/@Response;
- @Bean注解导入;
- @Import注解导入普通bean;
- 实现spring的FactoryBean
接口, 通过@Bean加入容器;
@Import导入普通bean也有四种方式:
- @Import(单个bean)
- @Import({多个bean-1, 多个bean-2, ...}
- @Import({bean1.class, bean2.class, ImportSelector.class})
- @Import({bean1.class, bean2.class, ImportSelector.class, ImportBeanDefinitionRegistrar.class})