Spring IOC 擴展點的簡單的應用

精通Spring主要看有沒有掌握好Spring的那些擴展點,以及如何使用他們。

以下代碼示例的倉庫的鏈接

使用BeanPostProcessor自定義Bean

如果您想在Spring容器完成實例化,配置和初始化bean之后實現(xiàn)一些自定義邏輯,則可以插入一個或多個自定義BeanPostProcessor實現(xiàn)。這些實現(xiàn)成為后置處理器。

BeanPostProcessor接口包含兩個回調(diào)方法。當實現(xiàn)此接口類通過容器注冊為后處理器時,由Spring容器實例的Bean,Spring容器會在bean 的init方法執(zhí)行前回調(diào)postProcessBeforeInitialization方法,然后會在bean初始化之后回調(diào)postProcessAfterInitialization方法。后置處理器可以對這些Bean做任何自定義操作。一些Spring Aop 的基礎實現(xiàn)類就是通過實現(xiàn)BeanPostProcessor從而提供代理包裝邏輯 。

Spring容器能夠自動檢測任何實現(xiàn)了BeanPostProcessor接口的Bean.容器會自動將這些bean注冊成后置處理器以便后續(xù)調(diào)用。

下面的示例演示如何在ApplicationContext中編寫,注冊和使用BeanPostProcessor實例(Spring AOP的實現(xiàn)方式就是如下)。

public interface Greeting {
    void sayHello();
}
public class StudentImpl implements Greeting {
    private String name;

    @Override
    public void sayHello() {
        System.out.println("Hello World,"+this.name);
    }

    public void init(){
        this.name="student";
    }

    @Override
    public String toString() {
        return "HelloWorldImpl{" +
                "name='" + name + '\'' +
                '}';
    }
}
public class TeacherImpl implements Greeting {
    private String name;

    @Override
    public void sayHello() {
        System.out.println("Hello World,"+this.name);
    }

    public void init(){
        this.name="teacher";
    }

    @Override
    public String toString() {
        return "TeacherImpl{" +
                "name='" + name + '\'' +
                '}';
    }
}
public class HelloWorldBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("BeanPostProcessor織入,Spring AOP 實現(xiàn)原理");
                return method.invoke(bean, args);
            }
        });
    }
}
<?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">

    <!-- Root Context: defines shared resources visible to all other web components -->
    <bean id="student" class="com.gethin.extension.example1.StudentImpl" init-method="init" />

    <bean id="teacher" class="com.gethin.extension.example1.TeacherImpl" init-method="init" />

    <bean id="hellWorldBeanPostPostProcessor" class="com.gethin.extension.example1.HelloWorldBeanPostProcessor"/>
</beans>

執(zhí)行入口:

public class Main {
    public static void main(String args[]) {
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("example1.xml");
        Greeting student= (Greeting) applicationContext.getBean("student");
        student.sayHello();
        Greeting teacher= (Greeting) applicationContext.getBean("teacher");
        teacher.sayHello();
    }
}

上面程序執(zhí)行的結(jié)果如下:

BeanPostProcessor織入,Spring AOP 實現(xiàn)原理
Hello World,student
BeanPostProcessor織入,Spring AOP 實現(xiàn)原理
Hello World,teacher

使用BeanFactoryPostProcessor自定義配置元數(shù)據(jù)

BeanFactoryPostProcessor跟BeanPostProcessor有點相似,但是有一個很明顯的區(qū)別,BeanFactoryPostProcessor 主要是作用于Bean的配置元數(shù)據(jù)。Spring IoC容器允許BeanFactoryPostProcessor讀取配置元數(shù)據(jù),并有可以在容器實例化除BeanFactoryPostProcessor實例之外的任何bean之前更改配置元數(shù)據(jù)。

下面示例,如何通過BeanFactoryPostProcessor動態(tài)注冊Bean進去。

public class User {
private String id;
private String name;
//getter,setter省略
}
/**
 * Created with IntelliJ IDEA.
 *
 * @author: gethin
 * @Date: 2020/4/5 21:04
 * @description: BeanFactoryPostProcessor 實現(xiàn)自動注冊User的bean上去
 */
public class HelloWorldBeanPostFactoryProcesser implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        DefaultListableBeanFactory defaultListableBeanFactory= (DefaultListableBeanFactory) configurableListableBeanFactory;
        BeanDefinitionBuilder beanDefinitionBuilder=BeanDefinitionBuilder.genericBeanDefinition(User.class);
        beanDefinitionBuilder.addPropertyValue("id", new Integer(1));
        beanDefinitionBuilder.addPropertyValue("name", "gethin");
        defaultListableBeanFactory.registerBeanDefinition("user",beanDefinitionBuilder.getBeanDefinition());
    }
}
<?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="helloWorldBeanPostFactoryProcesser" class="com.gethin.extension.example2.HelloWorldBeanPostFactoryProcesser"/>
</beans>

程序入口,獲取User并輸出。

/**
 * Created with IntelliJ IDEA.
 *
 * @author: gethin
 * @Date: 2020/3/15 22:13
 * @description:
 */
public class Main {
    public static void main(String args[]) {
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("example2.xml");
        User user= (User) applicationContext.getBean("user");
        System.out.println(user.toString());
    }
}

程序輸出結(jié)果,如下。

User{id='1', name='gethin'}

使用FactoryBean自定義實例化邏輯

您可以為本身就是工廠的對象實現(xiàn)FactoryBean接口。

FactoryBean接口是可插入Spring IoC容器的實例化邏輯的一點。
如果您有復雜的初始化代碼,可以用Java更好地表達,則可以創(chuàng)建自己的FactoryBean,在該類中編寫復雜的初始化,然后將自定義FactoryBean插入容器。

FactoryBean接口提供了三種方法:

  • Object getObject():返回此工廠創(chuàng)建的對象的實例。
    實例可以共享,具體取決于該工廠是否返回單例或原型。
  • boolean isSingleton():如果此FactoryBean返回單例,則返回true,否則返回false。
  • getObjectType():返回由getObject()方法返回的對象類型;如果類型未知,則返回null。

Mybatis與Spring整合,Mybatis的mapper對象也是通過FactoryBean來實例化的。下面通過簡單的例子,實現(xiàn)這一原理。

定義自己的Mapper注解。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Mapper {
}

創(chuàng)建模擬的Mapper接口類,PersonMapper和UserMapper都是接口,沒有具體實現(xiàn)。

@Mapper
public interface PersonMapper {
    void getPerson();
}

創(chuàng)建MapperFatoryBean實現(xiàn)FatoryBean,重寫3個方法實現(xiàn)MapperBean的特殊實例方式(通過JDK代理實例)。

@Component
public class MapperFactoryBean<T> implements FactoryBean<T> {

    private Class<T> mapperInterface;

    @Override
    public T getObject() throws Exception {
        return (T)Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, (proxy, method, args) -> {
            System.out.println( mapperInterface.getSimpleName() +"的代理類對象");
            return null;
        });
    }

    @Override
    public Class<?> getObjectType() {
        return mapperInterface;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    public void setMapperInterface(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }
}
/**
 * Created with IntelliJ IDEA.
 *
 * @author: gethin
 * @Date: 2020/4/6 1:06
 * @description: 掃描包并進行Bean的注冊
 */
public class MapperScanner extends ClassPathBeanDefinitionScanner {
    public MapperScanner(BeanDefinitionRegistry registry) {
        super(registry);
        addIncludeFilter(new AnnotationTypeFilter(Mapper.class));
    }
    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> mapperBeanDefinitionHolders = super.doScan(basePackages);
        for (BeanDefinitionHolder mapperBeanDefinitionHolder : mapperBeanDefinitionHolders) {
            GenericBeanDefinition mapperBeanDefinition= (GenericBeanDefinition) mapperBeanDefinitionHolder.getBeanDefinition();
            MutablePropertyValues propertyValues = mapperBeanDefinition.getPropertyValues();
            propertyValues.add("mapperInterface", mapperBeanDefinition.getBeanClassName());
            mapperBeanDefinition.setBeanClass(MapperFactoryBean.class);
        }
        return mapperBeanDefinitionHolders;
    }
    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        AnnotationMetadata metadata = beanDefinition.getMetadata();
        return (metadata.isInterface() && metadata.isIndependent());
    }
}

MapperBean通過實現(xiàn)BeanFactoryPostProcessor,將FactoryBean注冊到容器中去。

/**
 * Created with IntelliJ IDEA.
 *
 * @author: gethin
 * @Date: 2020/4/6 1:00
 * @description:
 */
public class MapperBean implements BeanFactoryPostProcessor {
    private String package2Scan;
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        MapperScanner mapperScanner=new MapperScanner((BeanDefinitionRegistry) configurableListableBeanFactory);
        mapperScanner.doScan(package2Scan);
    }
    public void setPackage2Scan(String package2Scan) {
        this.package2Scan = package2Scan;
    }
}

程序執(zhí)行入口,mapper接口方法執(zhí)行。

/**
 * Created with IntelliJ IDEA.
 *
 * @author: gethin
 * @description:
 */
public class Main {
    public static void main(String args[]) {
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("example3.xml");
        UserMapper userMapper= applicationContext.getBean(UserMapper.class);
        userMapper.getUser(1);
        PersonMapper personMapper=applicationContext.getBean(PersonMapper.class);
        personMapper.getPerson();
    }
}

程序輸出,mapper接口執(zhí)行成功。

UserMapper的代理類對象
PersonMapper的代理類對象

總結(jié)

Spring IOC提供的拓展接口有以下3個,其他很多擴展也都是在此基礎上進行提供。

  • BeanPostProcessor
  • BeanFactoryPostProcessor
  • FactoryBean
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容