BeanPostProcessor、BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor与ImportBeanDefinitionRegistrar接口的应用

一、BeanPostProcessor

主要负责bean的初始化前后进行前后置处理:

 1 public interface BeanPostProcessor {
 2 
 3     @Nullable
 4     default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
 5         return bean;
 6     }
 7 
 8     @Nullable
 9     default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
10         return bean;
11     }
12 
13 }

该接口在文章https://www.cnblogs.com/wangYB/p/14777035.html已经介绍过了,这里就不重复介绍了,需要注意的是,每个bean初始化前后都会调用这个接口的实现类方法。

二、BeanFactoryPostProcessor

1、接口

通过获取beanFactory可以修改beanFactory中的bean信息,如修改bean的属性值、实现bean的动态代理:

1 @FunctionalInterface
2 public interface BeanFactoryPostProcessor {
3 
4     void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
5 
6 }

2、示例

(1)示例1:修改bean的属性值

通过获取beanFactory,获取spring注册的bean,进而修改bean的属性值。

public interface MessageService {
    
    String getMessage();
}

public class MessageServiceImpl implements MessageService {

    private String msg;


    public void setMsg(String msg) {
        this.msg = msg;
    }


    @Override
    public String getMessage() {
        return msg;
    }
}


public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition definition = beanFactory.getBeanDefinition("messageService");
        definition.getPropertyValues().addPropertyValue("msg", "456");//这里将该bean的msg属性值修改为"456"
    }

}

bean配置:

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3        xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
 4        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"
 5 >
 6 
 7     <bean id="messageService" class="com.spring.service.MessageServiceImpl" >
 8         <property name="msg" value="111"/>
 9     </bean>
10 
11     <bean id="testBeanFactoryPostProcessor" class="com.spring.processor.TestBeanFactoryPostProcessor"/>
12 
14 </beans>

启动并获取msg值:

 1 public class Test {
 2     
 3     public static void main(String[] args) {
 4          // 用我们的配置文件来启动一个 ApplicationContext
 5         ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");
 6  8         MessageService messageService = (MessageService)context.getBean("messageService");
 9 
10         System.out.println(messageService.getMessage());
11 
12         ((ClassPathXmlApplicationContext) context).close();
13     }
14 
15 }

运行结果:

 可见,原xml中配置的属性值已经被修改.。

(2)示例二:bean的动态代理

 通过FactoryBean<T>接口,创建对应bean的代理对象,注册到beanFactory中,以给Car装Wheel为例:

 1 public interface Wheel {
 2     void run();
 3 }
 4 
 5 public class Car {
 6 
 7     private Wheel wheel;
 8 
 9     public Wheel getWheel() {
10         return wheel;
11     }
12 
13     public void setWheel(Wheel wheel) {
14         this.wheel = wheel;
15     }
16 
17     public void start(){
18         wheel.run();
19     }
20 
21 }
22 
23 
24 public class WheelFactory implements FactoryBean<Wheel>,InvocationHandler {
25 
26     @Override
27     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
28         System.out.println("代理类方法被调用|method="+method.getName());
29 
30         return null;
31     }
32 
33     @Override
34     public Wheel getObject() throws Exception {
35         System.out.println("获取Engine动态代理");
36         return (Wheel) Proxy.newProxyInstance(this.getClass().getClassLoader(),new Class[]{Wheel.class},this);
37     }
38 
39     @Override
40     public Class<?> getObjectType() {
41         return Wheel.class;
42     }
43 }
44 
45 public class DynamicProxyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
46 
47     @Override
48     public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
49         BeanDefinitionRegistry registry=(BeanDefinitionRegistry) beanFactory;
50         GenericBeanDefinition beanDefinition=new GenericBeanDefinition();
51         beanDefinition.setBeanClass(WheelFactory.class);
52         beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
53         beanDefinition.setAutowireCandidate(true);
54         registry.registerBeanDefinition("wheel",beanDefinition);
55     }
56 
57 }
58 
59 
60 @Configuration
61 public class BeanConfiguration {
62 
63     @Bean
64     public Car car(Wheel wheel){
65         Car car=new Car();
66         car.setWheel(wheel);
67         return car;
68     }
69 }

xml配置:

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans" 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 https://www.springframework.org/schema/context/spring-context.xsd"
>

    <bean id="dynamicProxyBeanFactoryPostProcessor" class="com.spring.processor.dynamicproxy.DynamicProxyBeanFactoryPostProcessor"/>

    <context:component-scan base-package="com.spring"/>
</beans>

调用:

public class Test {
    
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");

        Car car=(Car)context.getBean("car");
        car.start();
        ((ClassPathXmlApplicationContext) context).close();
    }

}

执行结果:

 可见,调用到了代理类的invoke方法,即代理类通过factoryBean注册成功。

三、BeanDefinitionRegistryPostProcessor

1、接口

实现了bean的动态注入,且继承了BeanFactoryPostProcessor接口

1 public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
2 
3   postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
4 
5 }

我们查看一下传入的BeanDefinitionRegistey类:

public interface BeanDefinitionRegistry extends AliasRegistry {

    /**
     * Register a new bean definition with this registry.
     * Must support RootBeanDefinition and ChildBeanDefinition.
     * @param beanName the name of the bean instance to register
     * @param beanDefinition definition of the bean instance to register
     * @throws BeanDefinitionStoreException if the BeanDefinition is invalid
     * @throws BeanDefinitionOverrideException if there is already a BeanDefinition
     * for the specified bean name and we are not allowed to override it
     * @see GenericBeanDefinition
     * @see RootBeanDefinition
     * @see ChildBeanDefinition
     */
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException;

    /**
     * Remove the BeanDefinition for the given name.
     * @param beanName the name of the bean instance to register
     * @throws NoSuchBeanDefinitionException if there is no such bean definition
     */
    void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    /**
     * Return the BeanDefinition for the given bean name.
     * @param beanName name of the bean to find a definition for
     * @return the BeanDefinition for the given name (never {@code null})
     * @throws NoSuchBeanDefinitionException if there is no such bean definition
     */
    BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    /**
     * Check if this registry contains a bean definition with the given name.
     * @param beanName the name of the bean to look for
     * @return if this registry contains a bean definition with the given name
     */
    boolean containsBeanDefinition(String beanName);

    /**
     * Return the names of all beans defined in this registry.
     * @return the names of all beans defined in this registry,
     * or an empty array if none defined
     */
    String[] getBeanDefinitionNames();

    /**
     * Return the number of beans defined in the registry.
     * @return the number of beans defined in the registry
     */
    int getBeanDefinitionCount();

    /**
     * Determine whether the given bean name is already in use within this registry,
     * i.e. whether there is a local bean or alias registered under this name.
     * @param beanName the name to check
     * @return whether the given bean name is already in use
     */
    boolean isBeanNameInUse(String beanName);

}

可见,该类提供了bean的注册、修改、删除操作,可以动态修改spring中的bean。

2、示例

创建一个BeanDefinitionRegistryPostProcessor 接口的实现类,在实现方法中创建beanDefinition,并注册到BeanDefinitionRegistry中:

public class User {

    private String name;

    private int age;

    User(String name,int age){
        this.name=name;
        this.age=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;
    }
}


public class TestBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

        AbstractBeanDefinition definition = BeanDefinitionBuilder.rootBeanDefinition(User.class)
                .addConstructorArgValue("张三")
                .addConstructorArgValue(26)
                .getBeanDefinition();
        registry.registerBeanDefinition("testUserBean", definition);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }

}

xml配置:

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans" 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 https://www.springframework.org/schema/context/spring-context.xsd"
>
    <bean id="testBeanDefinitionRegistryPostProcessor" class="com.spring.processor.TestBeanDefinitionRegistryPostProcessor"/>

</beans>

访问:

public class Test {
    
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");

        User user=(User)context.getBean("testUserBean");
        System.out.println("name="+user.getName()+",age="+user.getAge());
        ((ClassPathXmlApplicationContext) context).close();
    }

}

结果:

 可见在实现类的postProcessBeanDefinitionRegistry()方法中的testUserBean创建成功,在实际的使用中,该方法经常与ClassPathBeanDefinitionScanner结合使用,通过指定扫描包来扫描要创建的bean,并注册到BeanDefinitionRegistry中。

四、 ImportBeanDefinitionRegistrar

1、接口

相比较BeanDefinitionRegistryPostProcessor接口而言,ImportBeanDefinitionRegistrar的方法多传了一个AnnotationMetadata,用于从注解配置中读取出待创建bean的元数据,读取成功后将对应的bean注册到BeanDefinitionRegistry中:

1 public interface ImportBeanDefinitionRegistrar {
2 
3     public void registerBeanDefinitions(
4             AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
5 
6 }

 2、示例

以下演示通过注解配置指定bean的属性并写入到bean中:

public class TestImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        AnnotationAttributes annotationAttributes=AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(TestRegisterAnnotation.class.getName()));
        String userName=annotationAttributes.getString("userName");

        AbstractBeanDefinition definition = BeanDefinitionBuilder.rootBeanDefinition(User.class)
                .addConstructorArgValue(userName)
                .addConstructorArgValue(26)
                .getBeanDefinition();
        registry.registerBeanDefinition("testUserBean", definition);
    }

}


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(TestImportBeanDefinitionRegistrar.class)
public @interface TestRegisterAnnotation {
    String userName() default "";
}

//注解里指定属性参数
@Configuration
@TestRegisterAnnotation(userName = "赵云")
public class TestBeanConfiguration {

}

xml配置扫描包:

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans" 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 https://www.springframework.org/schema/context/spring-context.xsd"
>
    <context:component-scan base-package="com.spring"/>
</beans>

打印输出bean信息:

public class Test {
   
   public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");
        User user=(User)context.getBean("testUserBean");
        System.out.println("name="+user.getName()+",age="+user.getAge());
      ((ClassPathXmlApplicationContext) context).close();
   }

}

结果:

 

 可见,注解中配置的bean属性已经生效。

 

posted @ 2021-06-02 16:28  书剑江山  阅读(453)  评论(0)    收藏  举报