1.美图
2.概述
Spring的面试中,一般都会问到IOC和AOP,大部分同学都能回答出这些知识点的基本运用,如果再多问一句,AOP的底层实现方式,大部分人都会回答动态代理。那么动态代理是如何被使用到Bean上的呢?到这里可能要刷掉一大部分人,如果没有看过Spring的源码的话,这个是比较难回答的。
实际就是今天要了解的BeanPostProcessor,这是一个比较神奇的接口,实现AOP功能主要就是依靠这个接口。
在Spring官方文档中,这两个知识点被当做扩展知识点来介绍的。
3.BeanPostProcessor
3.1 定义
该接口定义了两个回调方法用于用户实现,我们可以在里面定义一系列的实现。
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
如果我们自定义了BeanPostProcessor的实现,并注册到容器中,则bean的加载过程中,相关方法的调用顺序为:
- 容器实例化bean
- 调用
BeanPostProcessor.postProcessBeforeInitialization()
前置方法 - 调用bean的初始化方法
- 调用
BeanPostProcessor.postProcessAfterInitialization()
后置方法
Spring提供了这么一个接口,允许我们自定义实现,我们可以在自己的实现中修改bean相关属性,打印日志等一系列操作。
3.2 使用
下面通过一个示例看下BeanPostProcessor的使用
3.2.1 定义BeanPostProcessor实现
package com.spring.boot.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* Description:
*
* @author lcc
* @version 1.0
* @date 2020/1/9 11:03 上午
*/
public class HelloBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("before...");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("after...");
if (bean instanceof Student){
bean = (Student)bean;
((Student) bean).setName("test:" + ((Student) bean).getName());
}
return bean;
}
}
3.2.2 定义测试Bean
package com.spring.boot.bean;
import lombok.Data;
import java.io.Serializable;
/**
* Description:
*
* @author lcc
* @version 1.0
* @date 2020/1/9 11:04 上午
*/
@Data
public class Student implements Serializable {
private static final long serialVersionUID = -2088281526481179972L;
private int id;
private String name;
private int age;
public Student(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
System.out.println("allArgsConstructor...");
}
public Student() {
System.out.println("noArgsConstructor...");
}
public void init(){
System.out.println("student init...");
}
public void destroy(){
System.out.println("student destroy...");
}
}
3.2.3 将bean添加到容器中,使用JavaConfig的方式
package com.spring.boot.bean;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
/**
* Description:
*
* @author lcc
* @version 1.0
* @date 2020/1/9 11:05 上午
*/
@Configuration
public class SpringConfiguration {
@Bean(name = "stu", autowire = Autowire.BY_TYPE, initMethod = "init")
@Scope(value = "singleton")
public Student student() {
return new Student(11, "jack", 22);
}
@Bean
public HelloBeanPostProcessor helloBeanPostProcessor() {
return new HelloBeanPostProcessor();
}
}
3.2.4 测试
测试程序
package com.spring.boot.bean;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import static org.junit.Assert.*;
public class HelloBeanPostProcessorTest {
@Test
public void testProcessor(){
AnnotationConfigApplicationContext applicationContext
= new AnnotationConfigApplicationContext(SpringConfiguration.class);
Student bean = applicationContext.getBean(Student.class);
System.out.println(bean);
}
}
测试结果
11:07:52.057 [main] INFO org.springframework.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean 'springConfiguration' of type [com.spring.boot.bean.SpringConfiguration$$EnhancerBySpringCGLIB$$eba6958a] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
11:07:52.094 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'stu'
allArgsConstructor...
before...
student init...
after...
Student(id=11, name=test:jack, age=22)
总结:通过结果可以看到我们之前所定义的结论是正确的。
先调用构造方法实例化bean,然后是BeanPostProcessor
的before
方法,紧接着就是Bean
的初始化方法(本例中的Student.init
),最后就是BeanPostProcessor
的after
方法
4.BeanFactoryPostProcessor
这个接口与我们上面的BeanPostProcessor
只差了一个Factory
,那么它们的功能呢?有什么相似点,又有什么不同点呢?
我们来看下Spring官方文档对其的描述
BeanFactoryPostProcessor operates on the bean configuration
metadata; that is, the Spring IoC container allows a
BeanFactoryPostProcessor to read the configuration metadata and
potentially change it before the container instantiates any
beans other than BeanFactoryPostProcessors.
主要就是说:BeanFactoryPostProcessor主要操作的是bean的元数据。
什么是bean的元数据?我们可以理解为这个bean有哪些属性,属性的类型,属性的scope等等。
4.1 案例
下面我们就来测试一下
4.1.1 实现接口BeanFactoryPostProcessor
package com.spring.boot.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
/**
* Description:
*
* @author lcc
* @version 1.0
* @date 2020/1/9 11:13 上午
*/
public class HelloBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("BeanFactoryPostProcessor.postProcessBeanFactory()");
String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
for (String beanName : beanDefinitionNames) {
if ("stu".equals(beanName)) {
BeanDefinition student = beanFactory.getBeanDefinition(beanName);
MutablePropertyValues propertyValues = student.getPropertyValues();
// 修改scope
student.setScope("prototype");
}
}
}
}
4.1.2 在SpringConfiguration中添加该bean
package com.spring.boot.bean;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
/**
* Description:
*
* @author lcc
* @version 1.0
* @date 2020/1/9 11:05 上午
*/
@Configuration
public class SpringConfiguration {
@Bean(name = "stu", autowire = Autowire.BY_TYPE, initMethod = "init")
@Scope(value = "singleton")
public Student student() {
return new Student(11, "jack", 22);
}
@Bean
public HelloBeanPostProcessor helloBeanPostProcessor() {
return new HelloBeanPostProcessor();
}
@Bean
public HelloBeanFactoryPostProcessor helloBeanFactoryPostProcessor(){
return new HelloBeanFactoryPostProcessor();
}
}
4.1.3 测试
@Test
public void testProcessor1(){
AnnotationConfigApplicationContext applicationContext
= new AnnotationConfigApplicationContext(SpringConfiguration.class);
Student bean = applicationContext.getBean(Student.class);
Student bean2 = applicationContext.getBean(Student.class);
System.out.println(bean);
System.out.println(bean == bean2);
}
测试结果
11:16:12.358 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@7c16905e
11:16:12.399 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
11:16:12.640 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
11:16:12.644 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'helloBeanFactoryPostProcessor'
11:16:12.646 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'springConfiguration'
11:16:12.653 [main] INFO org.springframework.context.annotation.ConfigurationClassEnhancer - @Bean method SpringConfiguration.helloBeanFactoryPostProcessor is non-static and returns an object assignable to Spring's BeanFactoryPostProcessor interface. This will result in a failure to process annotations such as @Autowired, @Resource and @PostConstruct within the method's declaring @Configuration class. Add the 'static' modifier to this method to avoid these container lifecycle issues; see @Bean javadoc for complete details.
11:16:12.674 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
BeanFactoryPostProcessor.postProcessBeanFactory()
11:16:12.679 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
11:16:12.682 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
11:16:12.689 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'helloBeanPostProcessor'
allArgsConstructor...
before...
student init...
after...
allArgsConstructor...
before...
student init...
after...
Student(id=11, name=test:jack, age=22)
false
可以看到,最终返回的是false,说明两次生成的对象不是同一个对象,也说明我们修改stu1这个bean的scope成功了。
5.官方对这两个接口的应用
BeanPostProcessor:AOP
BeanFactoryPostProcessor:PropertyPlaceholderConfigurer
来源:CSDN
作者:九师兄
链接:https://blog.csdn.net/qq_21383435/article/details/103902705