Spring - 钩子方法

1. 概述

Spring有很强的扩展性,主要体现在它为外界提供了许多钩子方法, 比如AwareBeanPostProcessorInitializingBeaninit-method 等都是 Spring 提供的扩展点

2. Aware 接口

spring源码:Aware接口
Spring 检测到 bean 实现了 Aware 接口,则会为其注入相应的依赖。所以通过让bean 实现 Aware 接口,则能在 bean 中获得相应的 Spring 容器资源。
Spring 中提供的 Aware 接口有:

BeanNameAware:注入当前 bean 对应 beanName
BeanClassLoaderAware:注入加载当前 beanClassLoader
BeanFactoryAware:注入 当前BeanFactory容器 的引用
ApplicationContextAware

如我们想得到当前的BeanFactory,我们可以让我们的实现类继承BeanFactoryAware接口,然后通过接口注入的方式得到当前容器中的BeanFactory

public class Fruit implements BeanFactoryAware {
    private BeanFactory beanFactory;
 
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
}

aware接口的各种处理是在属性设置完成之后、bean初始化之前完成的

3. InitializingBeanDisposableBean接口

InitializingBeanSpringbean 初始化提供的扩展点,可以添加自定义的初始化方法或者做一些资源初始化操作,当BeanFactory 设置完所有的Bean属性之后才会调用afterPropertiesSet方法

InitializingBean接口 的定义如下

public interface InitializingBean {
	void afterPropertiesSet() throws Exception;
}

DisposableBean接口只有一个方法destroy,作用是:当一个单例Bean实现DisposableBeandestroy可以添加自定义的一些销毁方法或者资源释放操作

4. init-method

指定 init-method 方法,指定初始化方法:

package com.minifull.pojo;

import org.springframework.beans.factory.BeanNameAware;

public class User implements BeanNameAware {
    private String name;
    private int age;

    public User() {
        System.out.println("Bean:初始化");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("设置属性");
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
    //调用BeanNameAware的setBeanName()
    //传递Bean的ID
    public void setBeanName(String name) {
        System.out.println("调用BeanNameAware的setBeanName()..." );
    }
    //Bean的初始化方法
    public void initUser() {
        System.out.println("Bean:initmethod");
    }

    //Bean的销毁方法
    public void destroyUser() {
        System.out.println("Bean:销毁");
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

public class MyBeanPostProcessor implements BeanPostProcessor {

    //对初始化之后的Bean进行处理
    //参数:bean:即将初始化的bean
    //参数:beanname:bean的名称
    //返回值:返回给用户的那个bean,可以修改bean也可以返回一个新的bean

    public Object postProcessAfterInitialization(Object bean, String beanname) throws BeansException {
        User user = null;
        System.out.println("后置处理器,将Bean的成员变量的值修改了");
        if("name".equals(beanname) || bean instanceof User) {
            user = (User) bean;
            user.setName("Jack");
        }
        return user;
    }

    //对初始化之前的Bean进行处理
    //参数:bean:即将初始化的bean
    //参数:beanname:bean的名称
    //返回值:返回给用户的那个bean,可以修改bean也可以返回一个新的bean

    public Object postProcessBeforeInitialization(Object bean, String beanname) throws BeansException {
        System.out.println("前置处理器,此时我的名字"+bean);
        return bean;
    }

}
<?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-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">


    <bean id="user" class="com.minifull.pojo.User" init-method="initUser" destroy-method="destroyUser">
        <property name="age" value="1"></property>
        <property name="name" value="minifull"></property>
    </bean>
    <!-- 配置bean的后置处理器,不需要id,IoC容器自动识别是一个BeanPostProcessor -->
    <bean class="com.minifull.pojo.MyBeanPostProcessor"></bean>

</beans>
public class FilAppTest {
    @Test
    public void test1(){
        ApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:applicationContext.xml");
        Object user = applicationContext.getBean("user");
        System.out.println(user);
        ((AbstractApplicationContext) applicationContext).close();

    }
    @Test
    public void dailyCircleTest(){

    }
}

在这里插入图片描述

5. 后置处理器

Spring的BeanFactoryPostProcessor和BeanPostProcessor
Spring框架中提供了各种PostProssor后置处理器,他们本身也是一种注册到容器中的Bean,其里面定义的方法会在特定的时机被容器调用,实现不改变容器或者Bean核心逻辑的情况下对Bean进行扩展,从而达到对Bean的包装,影响Bean的行为,修改Bean的内容等目的;

Spring提供的后置处理器大致分为容器级别的后置处理器和Bean级别的后置处理器

  • BeanDefinitionRegistryPostProcessor
  • BeanFactoryPostProcessor
  • BeanPostProcessor

BeanFactoryPostProcessor接口

public interface BeanFactoryPostProcessor {
 
	/**
	 * Modify the application context's internal bean factory after its standard
	 * initialization. All bean definitions will have been loaded, but no beans
	 * will have been instantiated yet. This allows for overriding or adding
	 * properties even to eager-initializing beans.
	 * @param beanFactory the bean factory used by the application context
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
 
}

Spring允许BeanFactoryPostProcessor在容器实例化任何其它bean之前读取配置元数据,并可以根据需要进行修改,例如可以把beanscopesingleton改为prototype,也可以把property的值给修改掉;它是在spring容器加载了bean的定义文件之后,在bean实例化之前执行的;

Spring允许可以同时配置多个BeanFactoryPostProcessor,并通过设置order属性来控制各个BeanFactoryPostProcessor的执行次序,看下面的例子
User


public class User implements BeanNameAware {
    private String name;
    private int age;
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

UserBeanFactoryPostProcessor

public class UserBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    /**
     *
     * @param beanFactory 从工厂中可以获取到相关bean的定义信息
     * @throws BeansException
     */
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("调用UserBeanFactoryPostProcessor的postProcessBeanFactory");
        BeanDefinition user = beanFactory.getBeanDefinition("user");
        String scope = user.getScope();
        System.out.println("User的是:"+scope);
        if(scope.equals(BeanDefinition.SCOPE_SINGLETON)){
            user.setScope(BeanDefinition.SCOPE_PROTOTYPE);
            System.out.println("更改为"+user.getScope());
        }
        //value
        MutablePropertyValues propertyValues = user.getPropertyValues();
        System.out.println("user.age:"+propertyValues.get("age"));
        System.out.println("将年龄更改为22");
        propertyValues.addPropertyValue("age",22);
        System.out.println("UserBeanFactoryPostProcessor的postProcessBeanFactory调用结束");
    }
}

applicationContext.xml

<?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-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
    <bean id="user" class="com.minifull.pojo.User" scope="singleton">
        <property name="name" value="minifull"></property>
        <property name="age" value="21"></property>
    </bean>
    <bean id="userBeanFactoryPostProcessor" class="com.minifull.postprocessorpag.UserBeanFactoryPostProcessor"></bean>
</beans>
@Test
public void beanFactoryPostProcessortest(){
    ApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:applicationContext.xml");
    User user = (User)applicationContext.getBean("user");
    System.out.println(user);
}

结果如下
在这里插入图片描述

BeanPostProcessor接口

BeanPostProcessor,可以在spring容器实例化bean之后,在执行bean的初始化方法前后,添加一些自己的处理逻辑。这里说的初始化方法,指的是下面两种:
bean实现了InitializingBean接口,对应的方法为afterPropertiesSet

② 在bean定义的时候,通过init-method设置的方法

public interface BeanPostProcessor {

	// 初始化前置处理
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	// 初始化后置处理
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

}

这一点在AbstractAutowireCapableBeanFactory创建bean的源码中有所表现

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
            throws BeanCreationException {

    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        // 1. 创建实例
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    ...

    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
        // 2. 装载属性
        populateBean(beanName, mbd, instanceWrapper);
        if (exposedObject != null) {
            // 3. 初始化
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
    }
    ...
}

在上面第 3 步 initializeBean(...) 方法中会调用 BeanPostProcessor 中的方法,如下:

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
   ...
   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
      // 1. 执行每一个 BeanPostProcessor 的 postProcessBeforeInitialization 方法
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }

   try {
      // 调用 bean 配置中的 init-method="xxx"
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   ...
   if (mbd == null || !mbd.isSynthetic()) {
      // 我们关注的重点是这里!!!
      // 2. 执行每一个 BeanPostProcessor 的 postProcessAfterInitialization 方法
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }
   return wrappedBean;
}

BeanPostProcessor的常用场景有:

  • 对于标记接口的实现类,进行自定义处理
  • 为当前对象提供代理实现。例如 Spring AOP 功能,生成对象的代理类,然后返回

使用如下:


/**
 * bean的后置处理器
 * 分别在bean的初始化前后对bean对象提供自己的实例化逻辑
 * postProcessAfterInitialization:初始化之后对bean进行增强处理
 * postProcessBeforeInitialization:初始化之前对bean进行增强处理
 *
 */
public class MyBeanPostProcessor implements BeanPostProcessor {

    //对初始化之后的Bean进行处理
    //参数:bean:即将初始化的bean
    //参数:beanname:bean的名称
    //返回值:返回给用户的那个bean,可以修改bean也可以返回一个新的bean

    public Object postProcessAfterInitialization(Object bean, String beanname) throws BeansException {
        User user = null;
        System.out.println("对初始化之后的Bean进行处理,将Bean的成员变量的值修改了");
        if("name".equals(beanname) || bean instanceof User) {
            user = (User) bean;
            user.setName("Jack");
        }
        return user;
    }

    //对初始化之前的Bean进行处理
    //参数:bean:即将初始化的bean
    //参数:beanname:bean的名称
    //返回值:返回给用户的那个bean,可以修改bean也可以返回一个新的bean

    public Object postProcessBeforeInitialization(Object bean, String beanname) throws BeansException {
        System.out.println("对初始化之前的Bean进行处理,此时我的名字"+bean);
        return bean;
    }

}
<?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-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">


    <bean id="user" class="com.minifull.pojo.User">
        <property name="age" value="1"></property>
        <property name="name" value="minifull"></property>
    </bean>
    <!-- 配置bean的后置处理器,不需要id,IoC容器自动识别是一个BeanPostProcessor -->
    <bean class="com.minifull.pojo.MyBeanPostProcessor"></bean>

</beans>

在这里插入图片描述

BeanPostProcessor的家庭成员
在这里插入图片描述
InstantationAwareBeanPostProcessor接口
这个接口的作用是在Bean的实例化的过程中给Bean加上额外的逻辑,注意这里说的是实例化的过程,是在初始化和赋上属性之前;
InstantationAwareBeanPostProcessor接口中定义了三个方法

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
	//在对象实例化之前调用,直接返回一个对象(如代理对象)来代替通过内置的实例化流程创建对象
	@Nullable
	default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		return null;
	}
	//在对象实例化完成后,执行populateBean之前,判断是否继续进行对属性赋值的流程
	default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
		return true;
	}

	//在Spring处理完默认的成员属性,应用到指定的bean之前进回调,可以用来检查和修改属性
	@Nullable
	default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
			throws BeansException {

		return null;
	}

}

也就是说bean的生命周期实际上是这样的

当调用getBean()

    1.调用InstantationAwareBeanPostProcessor的postProcessBeforeInstantation方法

    2.实例化bean

    3.调用InstantationAwareBeanPostProcessor的postProcessAfterInstantation方法(如果有返回值 则跳转到114.尝试设置属性:调用InstantationAwareBeanPostProcessor的postProcessPropertyValues-

    5.设置属性

    6.调用beanNameAware的setBeanName方法

    7.调用BeanFactoryAware的setBeanFacotroy方法

    8.之后初始化: 先调用BeanPostProcessor的postProcessBeforeInitializing()

    9.初始化,调用<init-method>指定的方法,或者是@PostConstruct方法

    10.调用InitializingBean的afterPropertySet()方法

    11.调用BeanPostProcessor的postProcessAfterInitializaiton()方法

如果bean是prototype型的,则直接返回这个bean

如果是singleton型的,则加入到Spring的缓存池中,下次调用直接从缓存池中取得

这些在AbstractAutowireCapableBeanFactory的源码中都有体现

@Override
	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		if (logger.isTraceEnabled()) {
			logger.trace("Creating instance of bean '" + beanName + "'");
		}
		RootBeanDefinition mbdToUse = mbd;
		//....省略无关代码
		try {
			//如果Bean配置了InstantiationAwareBeanPostProcessor接口,也就是初始化前和初始化后的处理器,则试图返回一个需要创建Bean的代理对象
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
		}

		try {
			//创建Bean的入口
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
		
		}
		catch (Throwable ex) {
		
		}
	}

可以看到在doCreateBean方法前会调用resolveBeforeInstantiation,我们所配置的InstantiationAwareBeanPostProcessor后置处理器就是在这里执行的,并且在执行InstantiationAwareBeanPostProcessor后置处理器后就会把生成的对象返回也就不再执行doCreateBean方法,即Spring的初始化bean的流程

	@Nullable
	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		//如果beforeInstantiationResolved还没有设置或者是false(说明还没有需要在实例化前执行的操作)
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
			// Make sure bean class is actually resolved at this point.
			//mbd.isSynthetic()默认是true,
			// 如果注册了InstantiationAwareBeanPostProcessors类型的BeanPostProcessor,
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
					//PostProcessorsBeforeInstantiation
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
					//PostProcessorsAfterInitialization
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}

BeanDefinitionRegistryPostProcessor接口

BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor接口

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
	//该方法用来注册更多的bean到spring容器中
	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
	
	//继承自BeanFactoryPostProcessor的方法 主要用来对bean定义做一些改变
	//void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

可以看到除了继承自BeanFactoryPostProcessorpostProcessBeanFactory方法以外,还有postProcessBeanDefinitionRegistry方法,他的参数BeanDefinitionRegistry提供了丰富的方法来操作bean定义,判断、注册、反注册,使用它来注册更多的beanspring容器中

@Configuration
public class CustomizedBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        Class<User> clazz = User.class;
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
        GenericBeanDefinition beanDefinition = (GenericBeanDefinition) builder.getRawBeanDefinition();
        registry.registerBeanDefinition("user",beanDefinition);
    }

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }
}

在对 BeanDefinitionRegistryPostProcessor里面的方法进行执行的时候,Spring使用了责任链模式//TODO

6. FactoryBean接口

Spring中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean,即FactoryBean,这两种Bean都被容器管理,但工厂Bean跟普通Bean不同,其返回的对象不是指定类的一个实例,其返回的是该FactoryBeangetObject方法所返回的对象;

Spring框架内部,有很多地方有FactoryBean的实现类,它们在很多应用如(SpringAOPORM,事务管理)及与其它第三框架(hibernatemybatisjpa…)集成时都有体现

public interface FactoryBean<T> {
	//返回由FactoryBean创建的bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中单实例缓存池中
	T getObject() throws Exception;

	//返回FactoryBean创建的bean类型
	Class<?> getObjectType();

	//返回由FactoryBean创建的bean实例的作用域是singleton还是prototype
	boolean isSingleton();

}

通过Spring容器的getBean()方法返回的不是FactoryBean本身,而是FactoryBean.getObject()方法所返回的对象,相当于 FactoryBean.getObject()代理了getBean()方法。如果希望获取FactoryBean的实例,则需要在使用getBean(beanName) 方法时在beanName前显示的加上 "&" 前缀

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值