JavaConfig注册bean
在javaConfig配置spring中,有两种方式将类对象注册到spring容器当中,不包含注解和xml配置
创建AnnotationConfigApplicationContext对象时可以传递参数,参数类型为类的class对象,这是第一种方式将对象放在spring容器中
//采用注解注解配置和javaconfig
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
同样还可以通过register
方法将想要放入spring容器的对象放进去,需要注意的是注册完还需要调用refresh
作刷新,否则就放不进去
//通过register这个方法可以直接注册一个对象到spring容器当中(不需要注解)
annotationConfigApplicationContext.register(UserTest.class);
annotationConfigApplicationContext.refresh();
我们找到第一方式spring的源码,可以发现这里同样调用了register
和refresh
方法,所以其实spring都是通过这两个方法将对象放入容器中的
/**
* Create a new AnnotationConfigApplicationContext, deriving bean definitions
* from the given annotated classes and automatically refreshing the context.
* @param annotatedClasses one or more annotated classes,
* e.g. {@link Configuration @Configuration} classes
*/
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
register方法
经过层层调用,我们进入doRegisterBean
方法,这里创建了一个AnnotatedGenericBeanDefinition对象,属于描述bean的对象,就相当于jdk中描述对象的class类对象一样。
//描述bean的对象,相当于jdk中对象与它的class类的关系
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
最后将abd和beanname放入bdh中,注意这个bdh并没有实际的意义,只是为了传值方便创造了一个容器一样,传入registerBeanDefinition
方法
//将abd和beanname放入bdh中,注意这个bdh并没有实际的意义,只是为了传值方便创造了一个容器一样
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
这里执行的是DefaultListableBeanFactory的registerBeanDefinition
方法
在这个方法中会将bean的描述和beanname以键值对的形式放入到一个map中,还把beanname单独放到一个list集合中
refresh方法
这里先重点看看prepareBeanFactory
方法,传入的是bean工厂
前面是一些初始化工作,注意addBeanPostProcessor
这个方法的作用是添加一个后置处理器,其底层实现是向list中添加元素
添加进去的对象是一个实现了BeanPostProcessor接口的对象,也证实了这就是一个后置处理器
我们可以通过实现BeanPostProcessor接口,重写其中的方法,并且将这个对象加入到spring容器中,我们也可以插手spring生成bean的过程。不过这只是扩展的方式之一。
实现后置处理器扩展bean(BeanPostProcessor)
可以看到实现了BeanPostProcessor的类有太多太多,也就是说spring自身也通过这个方式扩展bean的生产过程
这里实现了对UserTest对象的简单扩展,这里的方法是直接把bean传给了使用者,所以使用者可以直接对bean进行操作,这也意味着实现这个接口可以插手spring的bean实例化过程
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof UserTest){
System.out.println("postProcessBeforeInitialization");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof UserTest){
System.out.println("postProcessAfterInitialization");
}
return bean;
}
}
public class UserTest {
public UserTest(){
System.out.println("UserTest");
}
@PostConstruct
public void init(){
System.out.println("init");
}
public void test(){
System.out.println("test");
}
}
public static void main(String[] args) {
//采用注解注解配置和javaconfig
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
//通过register这个方法可以直接注册一个对象到spring容器当中(不需要注解)
annotationConfigApplicationContext.register(UserTest.class);
UserTest userTest = annotationConfigApplicationContext.getBean(UserTest.class);
userTest.test();
}
结果执行的顺序如下
UserTest
postProcessBeforeInitialization
init
postProcessAfterInitialization
test
而且这种扩展的类也可以不止一个,那么就有一个顺序的问题,需要通过实现PriorityOrdered接口来排序,那么就需要实现接口的方法getOrder
其中返回的值的大小就决定了这些bean的初始化顺序,越小就表示越前。
@Override
public int getOrder() {
return 101;
}
bean的类型
- 注解实现的bean
- xml实现的baen
- JavaConfig中@bean注解定义的bean
- spring内部自己的bean