Spring之后处理器(自定义)

两种后处理器:

Bean后处理器,实现BeanPostProcessor接口

BeanFactory后处理器,实现BeanFactoryPostProcessor接口,也称为容器后处理器。

BeanPostProcessor

1、简介

Bean后处理器用来对bean的功能进行扩展、增强,对IoC容器中的所有bean都有效。

时机:执行初始化方法之前和之后处理。

生命周期如下:

代码块-->实例化-->数据装配-->初始化之前-->初始化方法-->初始化之后-->就绪-->使用-->销毁方法-->从容器中销毁

从上边bean的声明周期可见,在实例化、数据装配之后操作,因此叫做后处理器。

2、实现步骤

1、定义一个类,实现BeanPostProcessor接口

2、将该后处理器添加到IoC容器中

<?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">

        <!--BeanPostProcessor-->
        <bean id="springBean" class="ioc22.SpringBean" init-method="init">

        </bean>
        <bean id="otherBean" class="ioc22.OtherBean" init-method="init">

        </bean>
        <!--将SpringBeanPostProcessor后处理器加入到IoC中-->
        <bean class="ioc22.SpringBeanPostProcessor"/>
</beans>
package ioc22;

public class SpringBean {
    void init(){
        System.out.println("SpringBean.SpringBean");
    }
}
package ioc22;

public class OtherBean {
    void init(){
        System.out.println("OtherBean.OtherBean");
    }
}
package ioc22;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class SpringBeanPostProcessor implements BeanPostProcessor {
    //在bean初始化之前执行
    @Override
    public Object postProcessBeforeInitialization(Object obj, String s) throws BeansException {
        System.out.println("SpringBeanPostProcessor.postProcessBeforeInitialization");
        return obj;
    }
    //在bean初始化之后执行
    @Override
    public Object postProcessAfterInitialization(Object obj, String s) throws BeansException {
        System.out.println("SpringBeanPostProcessor.postProcessAfterInitialization");
        return obj;
    }
}
package ioc22;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String [] args){
        ApplicationContext ac = new ClassPathXmlApplicationContext("ioc22/spring.xml");
    }
}

输出测试结果:

SpringBeanPostProcessor.postProcessBeforeInitialization
SpringBean.SpringBean
SpringBeanPostProcessor.postProcessAfterInitialization
SpringBeanPostProcessor.postProcessBeforeInitialization
OtherBean.OtherBean
SpringBeanPostProcessor.postProcessAfterInitialization

3、实际操练

需求:读取properties文件,为所有的bean注入值。

info.properties 

name=tom
pwd=123
email=tom@qq.com
phone=1888888
address=china

spring.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

        <!--练习:BeanPostProcessor-->
        <bean id="springBean" class="ioc23.SpringBean">
            <property name="username" value="${name}"/>
            <property name="password" value="${pwd}"/>
            <property name="email" value="${email}"/>
            <property name="phone" value="${phone}"/>
        </bean>

        <bean id="otherBean" class="ioc23.OtherBean">
            <property name="password" value="${pwd}"/>
            <property name="address" value="${address}"/>
        </bean>
        <bean class="ioc23.PropertiesPostProcessor">
            <property name="resource" value="classpath:ioc23/info.properties"/>
        </bean>
</beans>
package ioc23;

public class SpringBean {
    private String username;
    private String password;
    private String email;
    private String phone;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "SpringBean{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", email='" + email + '\'' +
                ", phone='" + phone + '\'' +
                '}';
    }
}

 

package ioc23;

public class OtherBean {
    private String password;
    private String address;

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "OtherBean{" +
                "password='" + password + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

 

package ioc23;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.io.Resource;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class PropertiesPostProcessor implements BeanPostProcessor {
    private Resource resource;

    public Resource getResource() {
        return resource;
    }

    public void setResource(Resource resource) {
        this.resource = resource;
    }

    @Override
    public Object postProcessBeforeInitialization(Object obj, String s) throws BeansException {
        return obj;//原样返回
    }

    //BeanPostProcessor是对IoC容器中的所有bean都有效
    //无法得到bean的属性,只能通过反射获取
    @Override
    public Object postProcessAfterInitialization(Object obj, String s) throws BeansException {
        //拿到对应的class对象
        Class<?> clazz = obj.getClass();
        //获取所有属性
        Field[] fields = clazz.getDeclaredFields();
        for (Field field:fields){
            //获取字段类型   类型可理解为类对象是啥
            Class<?> fieldType = field.getType();
            //只对字符串进行处理
            if (fieldType == String.class){
                //拿到属性的名字
                String name = field.getName();
                try {
                    //获取属性的值
                    field.setAccessible(true);
                    String s1 = field.get(obj).toString(); // ${name}
                    String value = reValue(s1);
                    field.set(obj,value);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }else {
                throw new RuntimeException("不支持的注入类型!");
            }
        }

        return obj;
    }
    public String reValue(String value){
        String regex = "\\$\\{(.*)\\}";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(value);
        if (matcher.matches()){
            //只有一个组${},所以group(1)就是key
            String key = matcher.group(1);  //拿到属性名称
            return getProperty(key);
        }
        return value;
    }
    private String getProperty(String key){
        Properties p = new Properties();
        try {
            p.load(resource.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
        //properties中是否有相应的key
        if (p.containsKey(key)){
            return p.getProperty(key);
        }else {
            throw new RuntimeException("未找到对应的key");
        }
    }
}
package ioc23;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String [] args){
        ApplicationContext ac = new ClassPathXmlApplicationContext("ioc23/spring.xml");
        System.out.println(ac.getBean("springBean"));
        System.out.println(ac.getBean("otherBean"));
    }
}

 测试输出

SpringBean{username='tom', password='123', email='tom@qq.com', phone='1888888'}
OtherBean{password='123', address='china'}

BeanFactoryPostProcessor

1、简介

容器后处理器,在bean创建之前修改bean 的定义属性( 读取bean中的元数据,根据需要进行修改),对IoC容器中所有bean有效。

生命周期如下:

BeanFactoryPostProcessor-->代码块-->实例化-->数据装配-->初始化之前-->初始化方法-->初始化之后-->就绪-->使用-->销毁方法-->从容器中销毁

注意:BeanFactoryPostProcessor中干的活是注册相应的属性编辑器,在后边装配的时候,spring框架会对匹配的属性通过这里注册的属性编辑器处理。不要以为是修改了属性点值,看看上边的声明周期就明白了。

2、实现步骤

1、定义一个类,实现BeanFactoryPostProcessor接口。

2、将该bean添加到IoC容器中。

3、定义属性编辑器PropertyEditor(转换器),实现PropertyEditor接口或继承PropertyEditorSupport父类。

4、在容器后处理器中注册属性编辑器

数据装配过程如下:

<?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">

        <!--最开始的方法:springBean中注入address-->
        <!--<bean id="address" class="ioc24.Address">
            <property name="city" value="nanjing"/>
            <property name="province" value="jiangsu"/>
        </bean>
        <bean id="springBean" class="ioc24.SpringBean">
            <property name="address" ref="address"/>
        </bean>-->
        <!--BeanFactoryPostProcessor-->
        <bean id="springBean" class="ioc24.SpringBean">
            <property name="address" value="[临沂-山东]"/>
        </bean>
        <!--将SpringBeanFacotoryPostProcessor添加到IoC容器中-->
        <bean class="ioc24.SpringBeanFacotoryPostProcessor"/>
</beans>
package ioc24;

public class Address {
    private String city;
    private String province;

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    @Override
    public String toString() {
        return "Address{" +
                "city='" + city + '\'' +
                ", province='" + province + '\'' +
                '}';
    }
}
package ioc24;

public class SpringBean {
    private Address address;

    public Address getAddress() {
        return address;
    }
    public void setAddress(Address address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "SpringBean{" +
                "address=" + address +
                '}';
    }
}
package ioc24.editor;

import ioc24.Address;

import java.beans.PropertyEditor;
import java.beans.PropertyEditorSupport;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/*
* 定义的属性编辑器
*/
//父类中方法较多,这里只需要重写getAsText   setAsText
public class AddressEditor extends PropertyEditorSupport {
    //用来将Address转换为String
    @Override
    public String getAsText() {
        return super.getAsText();
    }

    //将String转换为Address
    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        Pattern pattern = Pattern.compile("\\[(.*)-(.*)\\]");
        Matcher matcher = pattern.matcher(text);
        if (matcher.matches()){
            String city = matcher.group(1);
            String provience = matcher.group(2);
            Address address = new Address();
            address.setCity(city);
            address.setProvince(provience);
            //调用setValue设置值
            //说白了就是把修改属性之后的对象,交给容器
            setValue(address);
        }
    }
}
package ioc24;

import ioc24.editor.AddressEditor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

/**
 *定义容器后处理器
 * 作用:通过注册属性编辑器,完成属性的转换和装配
 *
 */

public class SpringBeanFacotoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("SpringBeanFacotoryPostProcessor.postProcessBeanFactory");
        //向容器中注册属性编辑器
        //第1个参数:要转换的属性类型   第2个参数:要使用的属性编辑器类型
        //该属性编辑器在装配的时候,如果遇到Address类型的数据要装配,那就把value值经过AddressEditor进行转换,将String转换成Address类型,完成装配
        configurableListableBeanFactory.registerCustomEditor(Address.class, AddressEditor.class);
    }
}
package ioc24;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String [] args){
        ApplicationContext ac = new ClassPathXmlApplicationContext("ioc24/spring.xml");
        System.out.println(ac.getBean("springBean"));
    }
}

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值