这些扩展其实是在初始过程中植入的钩子或回调method,主要看refresh方法
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
...
}
}
}
ApplicationListener
ApplicationListener 其实是 spring 事件通知机制中核心概念。
在java的事件机制中,一般会有三个概念:
- event object : 事件对象,描述事件本身一些属性
- event source :事件源,产生事件的地方
- event listener :监听具体的事件并作出响应
对应的在Spring事件传播机制中:
- 事件类:
ApplicationEvent
- 监听类:实现
ApplicationListener
接口 - 事件发布类,:实现
ApplicationEventPublisherAware
接口 - 将事件类和监听类交给Spring容器
例子
public class UserRegisterEvent extends ApplicationEvent {
public String name;
public UserRegisterEvent(Object o) {
super(o);
}
public UserRegisterEvent(Object o, String name) {
super(o);
this.name=name;
}
}
public class UserService implements ApplicationEventPublisherAware {
private ApplicationEventPublisher applicationEventPublisher;
public void setApplicationEventPublisher(ApplicationEventPublisher
applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
public void register(String name) {
System.out.println("用户:" + name + " 已注册!");
applicationEventPublisher.publishEvent(new UserRegisterEvent(name));
}
}
public class BonusServerListener implements
ApplicationListener<UserRegisterEvent> {
public void onApplicationEvent(UserRegisterEvent event) {
System.out.println("积分服务接到通知,给 " + event.getSource() +
" 增加积分...");
}
}
// 注册到容器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="userService" class="com.glmapper.extention.UserService"/>
<bean id="bonusServerListener"
class="com.glmapper.extention.BonusServerListener"/>
</beans>
public class MainTest {
public static void main(String[] args) {
ApplicationContext context =new
ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService)
context.getBean("userService");
//注册事件触发
userService.register("glmapper");
}
}
// 输出
用户:glmapper 已注册!
积分服务接到通知,给 glmapper 增加积分...
FactroyBean
XML 方式的 AOP 就是通过该接口实现的
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
boolean isSingleton();
}
Spring 在 IOC 初始化的时候,一般的Bean都是直接调用构造方法,而如果该Bean实现了FactoryBean 接口,则会调用该Bean的 getObject 方法获取bean,这也是Spring 使用此接口构造AOP的原因。在 IOC 调用此方法的时候,返回一个代理,完成AOP代理的创建。
BeanNameAware、ApplicationContextAware 和 BeanFactoryAware 针对bean工厂,可以获取上下文,可以获取当前bena的id
ApplicationContextAware
这个比较常用
ApplicationContextAware中只有一个setApplicationContext方法。实现了ApplicationContextAware接口的类,可以在该Bean被加载的过程中获取Spring的应用上下文ApplicationContext,通过ApplicationContext可以获取
Spring容器内的很多信息。
public class GlmapperApplicationContext implements
ApplicationContextAware {
private ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext
applicationContext) throws BeansException {
this.applicationContext=applicationContext;
}
public ApplicationContext getApplicationContext(){
return applicationContext;
}
}
BeanFactoryAware
我们知道BeanFactory是整个Ioc容器最顶层的接口,它规定了容器的基本行为。实现BeanFactoryAware接口就表明当前类具体BeanFactory的能力。
BeanFactoryAware接口中只有一个setBeanFactory方法。实现了BeanFactoryAware接口的类,可以在该Bean被加载的过程中获取加载该Bean的BeanFactory,同时也可以获取这个BeanFactory中加载的其它Bean。
有一个问题,我们为什么需要通过BeanFactory的getBean来获取Bean呢?Spring已经提供了很多便捷的注入方式,那么通过BeanFactory的getBean来获取Bean有什么好处呢?来看一个场景:写死的逻辑改为由动态配置决定
public interface HelloService {
void sayHello();
}
//英文打招呼实现
public class GlmapperHelloServiceImpl implements HelloService {
public void sayHello() {
System.out.println("Hello Glmapper");
}
}
//中文打招呼实现
public class LeishuHelloServiceImpl implements HelloService {
public void sayHello() {
System.out.println("你好,磊叔");
}
}
// 之前做法
if (condition=="英文"){
glmapperHelloService.sayHello();
}
if (condition=="中文"){
leishuHelloService.sayHello();
}
// 有没有什么方式可以动态的去决定客户端类到底去调用哪一种语言实现,而不是用过if-else方式来罗列呢?
// 是的,对于这些需要动态的去获取对象的场景,BeanFactoryAware就可以很好的搞定。
public class GlmapperBeanFactory implements BeanFactoryAware {
private BeanFactory beanFactory;
public void setBeanFactory(BeanFactory beanFactory) throws
BeansException {
this.beanFactory=beanFactory;
}
/**
* 提供一个execute 方法来实现不同业务实现类的调度器方案。
* @param beanName
*/
public void execute(String beanName){
HelloService helloService=(HelloService)
beanFactory.getBean(beanName);
helloService.sayHello();
}
}
//
public class HelloFacade {
private GlmapperBeanFactory glmapperBeanFactory;
//调用glmapperBeanFactory的execute方法
public void sayHello(String beanName){
glmapperBeanFactory.execute(beanName);
}
public void setGlmapperBeanFactory(GlmapperBeanFactory beanFactory){
this.glmapperBeanFactory = beanFactory;
}
}
public class MainTest {
public static void main(String[] args) {
ApplicationContext context = new
ClassPathXmlApplicationContext("beans.xml");
HelloFacade helloFacade = (HelloFacade)
context.getBean("helloFacade");
GlmapperBeanFactory glmapperBeanFactory = (GlmapperBeanFactory)
context.getBean("glmapperBeanFactory");
//这里其实可以不通过set方法注入到helloFacade中,
//可以在helloFacade中通过autowired
//注入;这里在使用main方法来执行验证,所以就手动set进入了
helloFacade.setGlmapperBeanFactory(glmapperBeanFactory);
//这个只需要传入不同HelloService的实现类的beanName,
//就可以执行不同的业务逻辑
helloFacade.sayHello("glmapperHelloService");
helloFacade.sayHello("leishuHelloService");
}
}
优化后只需要传入不同HelloService的实现类的beanName,就可以执行不同的业务逻辑
Bean 初始化顺序相关接口
验证Spring-Bean初始化顺序,先看几个关键接口
InitializingBean
Spirng的InitializingBean为bean提供了定义初始化方法的方式。InitializingBean是一个接口,它仅仅包含一个方法:afterPropertiesSet()。
在spring 初始化后,执行完所有属性设置方法(即setXxx)将自动调用 afterPropertiesSet(), 在配置文件中无须特别的配置, 但此方式增加了bean对spring 的依赖,应该尽量避免使用init-method(非接口)
Spring虽然可以通过InitializingBean完成一个bean初始化后对这个bean的回调,但是这种方式要求bean实现 InitializingBean接口。一但bean实现了InitializingBean接口,那么这个bean的代码就和Spring耦合到一起了。通常情况下我不鼓励bean直接实现InitializingBean,可以使用Spring提供的init-method的功能来执行一个bean 子定义的初始化方法。BeanFactoryPostProcessor接口
可以在spring的bean创建之前,修改bean的定义属性。也就是说,Spring允许BeanFactoryPostProcessor在容器实例化任何其它bean之前读取配置元数据,并可以根据需要进行修改,例如可以把bean的scope从singleton改为prototype,也可以把property的值给修改掉。可以同时配置多个BeanFactoryPostProcessor,并通过设置'order'属性来控制各个BeanFactoryPostProcessor的执行次序。
注意:BeanFactoryPostProcessor是在spring容器加载了bean的定义文件之后,在bean实例化之前执行的。接口方法的入参是ConfigurrableListableBeanFactory,使用该参数,可以获取到相关bean的定义信息BeanPostProcessor接口
BeanPostProcessor,可以在spring容器实例化bean之后,在执行bean的初始化方法前后,添加一些自己的处理逻辑。这里说的初始化方法,指的是下面两种:
1)bean实现了InitializingBean接口,对应的方法为afterPropertiesSet
2)在bean定义的时候,通过init-method设置的方法-
InstantiationAwareBeanPostProcessor
个接口实际上我们也是非常的熟悉,该接口在我们剖析注解配置AOP的时候是我们的老朋友,实际上,注解配置的AOP是间接实现 BeanPostProcess 接口的,而 InstantiationAwareBeanPostProcessor 就是继承该接口的。
例子
public class SpringIoCBean implements InitializingBean, BeanPostProcessor, BeanFactoryPostProcessor, BeanFactoryAware,
BeanNameAware, DisposableBean {
static {
System.out.println(" static block ");
}
private String hello;
{
System.out.println("{} block hello = " + hello);
}
public SpringIoCBean(){
System.out.println("调用HelloWorld构造器...");
}
public String getHello() {
return hello;
}
public void setHello(String hello) {
this.hello = hello;
System.out.println("调用setHello()...");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("调用BeanPostProcessor的postProcessBeforeInitialization() -- " + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("调用BeanPostProcessor的postProcessAfterInitialization() -- "+ beanName);
return bean;
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("调用InitializingBean的afterPropertiesSet()...");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory paramConfigurableListableBeanFactory)
throws BeansException {
System.out.println("调用BeanFactoryPostProcessor的postProcessBeanFactory()...");
}
@Override
public String toString() {
return "HelloWorld [hello=" + hello + "]";
}
@Override
public void setBeanName(String paramString) {
System.out.println("调用BeanNameAware.setBeanName paramString:"+paramString);
}
@Override
public void setBeanFactory(BeanFactory paramBeanFactory) throws BeansException {
System.out.println("调用BeanFactoryAware.setBeanFactory");
}
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean 接口 destroy方法");
}
public void init() throws Exception {
System.out.println("HelloWorld类 init-method 方法");
}
}
// 配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="springIoCBean" class="com.alicp.jetcache.test.spring.SpringIoCBean" init-method="init" >
<property name="hello" value="bigtest" />
</bean>
</beans>
// 测试类
@RunWith(SpringJUnit4ClassRunner.class) //使用junit4进行测试
@ContextConfiguration({"classpath:spring-bean.xml"}) //加载配置文件
public class SpringBeanIoCTest {
@Autowired
private SpringIoCBean bean;
@Test
public void testMain(){
System.out.println("testMain");
}
}
// ======输出
static block
{} block hello = null
调用HelloWorld构造器...
调用setHello()...
调用BeanNameAware.setBeanName paramString:springIoCBean
调用BeanFactoryAware.setBeanFactory
调用InitializingBean的afterPropertiesSet()...
HelloWorld类 init-method 方法
调用BeanFactoryPostProcessor的postProcessBeanFactory()...
调用BeanPostProcessor的postProcessBeforeInitialization() -- org.springframework.context.event.internalEventListenerProcessor
调用BeanPostProcessor的postProcessAfterInitialization() -- org.springframework.context.event.internalEventListenerProcessor
调用BeanPostProcessor的postProcessBeforeInitialization() -- org.springframework.context.event.internalEventListenerFactory
调用BeanPostProcessor的postProcessAfterInitialization() -- org.springframework.context.event.internalEventListenerFactory
调用BeanPostProcessor的postProcessBeforeInitialization() -- com.alicp.jetcache.spring.SpringBeanIoCTest
调用BeanPostProcessor的postProcessAfterInitialization() -- com.alicp.jetcache.spring.SpringBeanIoCTest
testMain
DisposableBean 接口 destroy方法
由结果得出初始化bean顺序
构造函数 construct
初始化属性 property
BeanNameAware : setBeanName
BeanFactoryAware : 接口执行setBeanFactory方法
InitializingBean 接口执行afterPropertiesSet方法
如果在配置文件中指定了init-method,那么执行该方法
如果实现了BeanFactoryPostProcessor 接口在 “new”其他类之前执行 postProcessBeanFactory 方法(通过这个方法可以改变配置文件里面的属性值的配置)// 该bean只会调用一次
如果实现了BeanPostProcessor 接口,那么会在其他bean初始化方法之前执行postProcessBeforeInitialization 方法,之后执行postProcessAfterInitialization方法 // 该bean会在每个其他bean初始化前后得到调用,所以可以用来过滤有关联的bean相应的处理