这儿提供一个我实验的源代码地址(有注释,如有错误,欢迎留言^_^,实验是检验真理的唯一标准):https://github.com/flycat0112/springArt
一、IOC容器
下面接口的执行顺序:BeanNameAware -> BeanClassLoaderAware -> BeanFactoryAware -> applyBeanPostProcessorsBeforeInitialization -> invokeInitMethods -> applyBeanPostProcessorsAfterInitialization
/**
* Initialize the given bean instance, applying factory callbacks
* as well as init methods and bean post processors.
* <p>Called from {@link #createBean} for traditionally defined beans,
* and from {@link #initializeBean} for existing bean instances.
* @param beanName the bean name in the factory (for debugging purposes)
* @param bean the new bean instance we may need to initialize
* @param mbd the bean definition that the bean was created with
* (can also be {@code null}, if given an existing bean instance)
* @return the initialized bean instance (potentially wrapped)
* @see BeanNameAware
* @see BeanClassLoaderAware
* @see BeanFactoryAware
* @see #applyBeanPostProcessorsBeforeInitialization
* @see #invokeInitMethods
* @see #applyBeanPostProcessorsAfterInitialization
*/
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
Ⅰ、自定义Bean的本质(对应项目的模块是spring-bean-lifecycle)
1、bean创建的时候做的操作(针对单个bean各自实现,不是所有bean):
org.springframework.beans.factory.InitializingBean 实现该接口,对bean创建之后做的操作。相等的注解:@PostConstruct
org.springframework.beans.factory.DisposableBean 实现该接口,对bean销毁前做的操作。相等的注解:@PreDestroy
ps:通过配置分别是init-method属性和destroy-method属性指定方法。设置默认的初始化方法和销毁方法可以通过配置中设置<Beans default-init-method="init"></Beans>这种形式。还有就是注解方式,通过实现接口方式,还有配置方式三种可以同时存在,他们的顺序是:先是注解,其次通过接口、最后是配置。
2、Bean的时间周期操作(针对所有单个Bean各自实现,但是,系统启动和结束才能调用,不受Bean的创建再次执行)
org.springframework.context.Lifecycle 其中申明了三个方法start(), stop(),isRunning()三个方法。isRunning方法是决定stop方法是否执行,返回true会执行。
org.springframework.context.Phased 其中申明了一个getPhase方法,这个方法是为了控制bean的初始化顺序和销毁的顺序,返回数字小的先初始化。通过Collections.sort(keys)来排序,进而控制执行顺序的。
org.springframework.context.SmartLifecycle 该加接口实现了Lifecycle和phased接口,宁外新加了isAutoStartup(), stop(Runnable run)两个方法。第一个方法如果返回true,spring容器刷新的时候就会执行start方法;第二个方法和Lifecycle不同提供run是因为提供一个有序地或者并发(多线程)的支持。
ps:上面的处理机制大概是这样,Lifecycle接口中stop方法是不会使用的,通常使用的SmartLifecycle接口额stop方法,这个处理机制只是org.springframework.context.LifecycleProcessor接口的默认实现org.springframework.context.support.DefaultLifecycleProcessor的实现机制。
3、LifecycleProcessor
org.springframework.context.LifecycleProcessor接口提供给ApplicationContext回调方法来刷新和关闭上下文(通过简单的委托的方式)
Ⅱ、Aware(对应项目的模块是spring-bean-aware)
org.springframework.context.ApplicationContextAware 中有setApplicationContext方法返回应用中当强使用的ApplicationContext接口的实现类。从其中获取查找我们想要的对象,写自己的方法,通过反射和业务代码解偶。
org.springframework.beans.factory.BeanNameAware 中有setBeanName方法返回当前实现的对象用key-value形式保存的spring容器中对应的key值。
ps:提供用户感知spring内部的对象。比如ApplicationContextAware提供ApplicationContext对象,BeanNameAware提供对象知道在spring容器里面保存对象的Key值(name)。spring-bena-aware的demo采用了应用实例,想通过委托的方式,方便地调用加密算法。
Ⅲ、容器拓展点(对应的模块spring-bean-expend)
org.springframework.beans.factory.config.BeanPostProcessor接口提供方法有postProcessBeforeInitialization,postProcessAfterInitialization两个。他们做操作是针对所有容器中的对象,不是只是针对本对象。ps: before方法在@PostConstruct、InitializingBean接口、init-method的对象执行之前,after在之后。源码调用情况查看开头源代码。
org.springframework.beans.factory.config.BeanFactoryPostProcessor 接口提供postProcessBeanFactory方法,针对创建Bean之前,只存在创建bean的配置文件,该接口可以对创建bean的参数进行修改,比如,对spring的jdbc配置里面使用参数(properties)文件,需要把值${}替换成参数文件里面对应的值,不能设置bean标签的属性,因为调用该对象前那个对象已经创建了。
org.springframework.beans.factory.FactoryBean接口提供一个创建Bean对象的工厂,方法有getObject,getObjectType,isSingleton。通过java代码创建复杂对象放到容器中。从容器中获取该对象只能通过“class”或者“注解”的方式从spring容器中获取对象,不能通过对象名称获取对象。
Ⅳ、spring注解(对应项目的模块是spring-bean-anntation)
@Required 设置set方法参数是否可以为null
@Primary 提升优先级
@Configuration 作用和@Component注解相同,但是@Configuration一般和@Bean一起用。
@Bean 功能和实现org.springframework.beans.factory.FactoryBean接口相似
@Autowired @Qualifier 确定详细的对象,@Autowired注解和@Resource注解的区别是,它要确定那个对象需要和@Qualifier来确定,并且,没有@Qualifier的话,默认通过类型来查找。
@Resource 默认通过变量名称来查找,如果变量是bean3,这儿找不到对象,报错。
@Scop 设置是单例,多例等
@DependsOn 设置bean的创建顺序。
ps:可以定义自己的基于@Qualifier注解作用相似的注解,用来详细确认一个对象来注入,可以自己定义其余的属性来确认。