欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring后處理器詳細(xì)介紹

 更新時間:2023年02月08日 11:32:42   作者:tanglin_030907031026  
Bean后置處理器允許在調(diào)用初始化方法前后對Bean進行額外的處理??梢栽?Spring容器通過插入一個或多個BeanPostProcessor的實現(xiàn)來完成實例化,配置和初始化一個?bean?之后實現(xiàn)一些自定義邏輯回調(diào)方法

一、概述

Spring的后處理器是Spring對外開發(fā)的重要擴展點、允許我們介入到Bean的整個實例化流程中來, 以達(dá)到動態(tài)注冊 BeanDefinition, 動態(tài)修改BeanDefinition, 以及動態(tài)修改Bean的作用。Spring主要有兩種后處理器:

  • BeanFactoryPostProcessor:Bean工廠后處理器, 在BeanDefinitionMap填充完畢, Bean實例化之前執(zhí)行;
  • BeanPostProcessor:Bean后處理器, 一般在Bean實例化之后, 填充到單例池singletonObjects之前執(zhí)行。

Bean工廠后處理器-BeanFactoryPostProcessor BeanFactoryPostProcessor是一個接口規(guī)范, 實現(xiàn)了該接口的類只要交由Spring容器管理的話, 那么Spring就會回調(diào)該接口的方法, 用于對BeanDefinition注冊和修改的功能。

BeanFactoryPostProcessor定義如下:

public interface BeanFactoryPostProcessor{
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) ;
}

二、案例演示

①:注冊BeanDefinition

1.編寫MyBeanFactoryPostProcessor類,實現(xiàn)BeanFactoryPostProcessor接口,并實現(xiàn)接口方法

package com.tangyuan.processor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("beanDefinitionMap填充完畢后回調(diào)該方法");
        //不在主xml文件中進行配置bean
        //動態(tài)注冊Beandifinition
          BeanDefinition beanDefinition=new RootBeanDefinition();
          beanDefinition.setBeanClassName("com.tangyuan.dao.impl.PeresonDaoImpl");                                     System.out.println(beanFactory);                       //org.springframework.beans.factory.support.DefaultListableBeanFactory@737996a0: defining beans
        //強轉(zhuǎn)成DefaultListableBeanFactory
        DefaultListableBeanFactory defaultListableBeanFactory= (DefaultListableBeanFactory) beanFactory;
        defaultListableBeanFactory.registerBeanDefinition("PersonDao",beanDefinition);
    }
}

2.測試

//創(chuàng)建ApplicationContext,加載配置文件,實例化容器
ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
PeresonDao bean = applicationContext.getBean(PeresonDao.class);
System.out.println(bean);//com.tangyuan.dao.impl.PeresonDaoImpl@6ddf90b0

②:注冊BeanDefinition

Spring提供了一個BeanFactoryPostProcessor的子接BeanDefinitionRegistryPostProcessor專門用于注冊BeanDefinition操作

public class MyBeanFactoryPostProcessor2 implements BeanDefinitionRegistryPostProcessor{
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException{}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException{
BeanDefinition beanDefinition=new RootBeanDefinition() ;
beanDefinition.setBeanClassName("com.tangyuan.dao.UserDaoImp12");
beanDefinitionRegistry.registerBeanDefinition("userDao2",beanDefinition) ;
}
}

案例演示:

1.編寫MyBeanDefinitionRegistryPostProcessor類,實現(xiàn)BeanDefinitionRegistryPostProcessor接口,并實現(xiàn)接口方法

package com.tangyuan.processor;
import com.alibaba.druid.support.spring.stat.SpringStatUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        System.out.println("MyBeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法");
        //向容器當(dāng)中注冊BeanDefinition
        BeanDefinition beanDefinition=new RootBeanDefinition();
        beanDefinition.setBeanClassName("com.tangyuan.dao.impl.PeresonDaoImpl");
         beanDefinitionRegistry.registerBeanDefinition("PersonDao",beanDefinition);
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("MyBeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法");
    }
}

2.將MyBeanDefinitionRegistryPostProcessor類在xml文件中進行配置

<bean class="com.tangyuan.processor.MyBeanDefinitionRegistryPostProcessor"></bean>

3.測試

//創(chuàng)建ApplicationContext,加載配置文件,實例化容器
ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
PeresonDao bean = applicationContext.getBean(PeresonDao.class);
System.out.println(bean);//com.tangyuan.dao.impl.PeresonDaoImpl@5a8e6209

ps:方法的執(zhí)行順序

1.MyBeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法

2.MyBeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法

3.MyBeanFactoryPostProcessor的postProcessBeanFactory方法

③:使用Spring的BeanFactoryPostProcessor擴展點完成自定義注解掃描

要求如下:

  • 自定義@MyComponent注解, 使用在類上;
  • 使用資料中提供好的包掃描器工具BaseClassScanUtils完成指定包的類掃描;
  • 自定義BeanFactoryPostProcessor完成注解@MyComponent的解析, 解析后最終被Spring管理。

1.創(chuàng)建一個OtherBean類,并定義@MyComponent注解

package com.tangyuan.beans;
import com.tangyuan.anno.MyComponent;
@MyComponent("OtherBean")
public class OtherBean {
}
package com.tangyuan.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyComponent {
    String value();
}

2.BaseClassScanUtils 幫助類編寫

package com.tangyuan.utils;
import com.tangyuan.anno.MyComponent;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class BaseClassScanUtils {
    //設(shè)置資源規(guī)則
    private static final String RESOURCE_PATTERN = "/**/*.class";
    public static Map<String, Class> scanMyComponentAnnotation(String basePackage) {
        //創(chuàng)建容器存儲使用了指定注解的Bean字節(jié)碼對象
        Map<String, Class> annotationClassMap = new HashMap<String, Class>();
        //spring工具類,可以獲取指定路徑下的全部類
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        try {
            String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                    ClassUtils.convertClassNameToResourcePath(basePackage) + RESOURCE_PATTERN;
            Resource[] resources = resourcePatternResolver.getResources(pattern);
            //MetadataReader 的工廠類
            MetadataReaderFactory refractory = new CachingMetadataReaderFactory(resourcePatternResolver);
            for (Resource resource : resources) {
                //用于讀取類信息
                MetadataReader reader = refractory.getMetadataReader(resource);
                //掃描到的class
                String classname = reader.getClassMetadata().getClassName();
                Class<?> clazz = Class.forName(classname);
                //判斷是否屬于指定的注解類型
                if(clazz.isAnnotationPresent(MyComponent.class)){
                    //獲得注解對象
                    MyComponent annotation = clazz.getAnnotation(MyComponent.class);
                    //獲得屬value屬性值
                    String beanName = annotation.value();
                    //判斷是否為""
                    if(beanName!=null&&!beanName.equals("")){
                        //存儲到Map中去
                        annotationClassMap.put(beanName,clazz);
                        continue;
                    }
                    //如果沒有為"",那就把當(dāng)前類的類名作為beanName
                    annotationClassMap.put(clazz.getSimpleName(),clazz);
                }
            }
        } catch (Exception exception) {
        }
        return annotationClassMap;
    }
    public static void main(String[] args) {
        Map<String, Class> stringClassMap = scanMyComponentAnnotation("com.tangyuan");
        System.out.println(stringClassMap);
    }
}

3.編寫MyComponentBeanFactoryPostProcessor類,并實現(xiàn)BeanDefinitionRegistryPostProcessor接口

package com.tangyuan.processor;
import com.tangyuan.utils.BaseClassScanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import java.util.Map;
public class MyComponentBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        //通過掃描工具去掃描指定包及其包下的所有類,收集使用@MyComponent注解的類
        Map<String, Class> map = BaseClassScanUtils.scanMyComponentAnnotation(
                "com.tangyuan"
        );
        //循環(huán)遍歷,組裝BeanDefinition進行注冊
        map.forEach((beanName,clazz)->{
       //獲取BeanClassName
            String name = clazz.getName();//com.tangyuan.beans.OtherBean
        //創(chuàng)建BeanDefinition
            BeanDefinition beanDefinition=new RootBeanDefinition();
            beanDefinition.setBeanClassName(name);
           //注冊
            beanDefinitionRegistry.registerBeanDefinition(name,beanDefinition);
        });
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
    }
}

4.在xml文件編寫MyComponentBeanFactoryPostProcessor類的bean

<bean class="com.tangyuan.processor.MyComponentBeanFactoryPostProcessor"></bean>

5.測試

OtherBean bean1 = applicationContext.getBean(OtherBean.class);
System.out.println(bean1);//com.tangyuan.beans.OtherBean@1877ab81

6.編寫一個BookBean類,并實現(xiàn)@MyComponent注解

package com.tangyuan.beans;
import com.tangyuan.anno.MyComponent;
import org.springframework.stereotype.Component;
@MyComponent("BookBean")
public class BookBean {
}

7.再次測試

//創(chuàng)建ApplicationContext,加載配置文件,實例化容器
ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
BookBean bean2 = applicationContext.getBean(BookBean.class);
System.out.println(bean2);//com.tangyuan.beans.BookBean@1877ab81

三、Bean的后處理器BeanPostProcessor

Bean被實例化后, 到最終緩存到名為singletonObjects單例池之前, 中間會經(jīng)過Bean的初始化過程, 例如:屬性的 填充、初始方法init的執(zhí)行等, 其中有一個對外進行擴展的點BeanPostProcessor,我們稱為Bean后處理。跟上面的 Bean工廠后處理器相似, 它也是一個接口, 實現(xiàn)了該接口并被容器管理的BeanPostProcessor, 會在流程節(jié)點上被 Spring自動調(diào)用。

BeanPostProcessor的接口定義如下:

public interface BeanPostProcessor{
@Nullable
//在屬性注入完畢, init初始化方法執(zhí)行之前被回調(diào)
default Object postProcesBeforeInitialization(Object bean, String bean Name)throws BeansException{
return bean;
}
//在初始化方法執(zhí)行之后, 被添加到單例池singletonObjects之前被回調(diào)
@Nullable
default Object postProcessAfterInitialization(Object bean, String bean Name) throws BeansException{
return bean;
}
}

案例:對Bean方法進行執(zhí)行時間日志增強

要求如下:

  • Bean的方法執(zhí)行之前控制臺打印當(dāng)前時間;
  • Bean的方法執(zhí)行之后控制臺打印當(dāng)前時間。

分析:

  • 對方法進行增強主要就是代理設(shè)計模式和包裝設(shè)計模式;
  • 由于Bean方法不確定, 所以使用動態(tài)代理在運行期間執(zhí)行增強操作;
  • 在Bean實例創(chuàng)建完畢后, 進入到單例池之前, 使用Proxy代替真是的目標(biāo)Bean

思路:編寫B(tài)eanPostProcessor, 增強邏輯編寫在after方法中

public Object post Process After Initialization(Object bean,String beanName) throws BeansException{
//Bean進行動態(tài)代理,返回的是Proxy代理對象
Object proxy Bean=Proxy.newProxyInstance(bean.getClass() .getClassLoader() ,
bean.getClass() .getInterfaces() ,
(Object proxy, Method method,Object[] args) ->{
long start=System.currentTimeMillis() ;
system.out.println("開始時間:"+new Date(start) ) ;
//執(zhí)行目標(biāo)方法BIN
Object result=method.invoke(bean,args) ;
long end=System.currentTimeMillis() ;
System.out.println("結(jié)束時間:"+new Date(end) ) ;
return result;
});
//返回代理對象
return proxy Bean;
}

實現(xiàn)代碼如下:

1.編寫一個TimeLogBeanPostProcessor類,接口BeanPostProcessor實現(xiàn),方法也實現(xiàn)

package com.tangyuan.processor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Date;
public class TimeLogBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return null;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
          //使用動態(tài)代理對目標(biāo)Bean進行增強,返回proxy對象,進而存儲到單例池singletonObjects中
            Object beanProxy= Proxy.newProxyInstance(
                bean.getClass().getClassLoader(),
                bean.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //1.輸出開始時間
                        System.out.println("方法:"+method.getName()+"-開始時間:"+new Date());
                        //2.執(zhí)行目標(biāo)方法
                        Object invoke = method.invoke(bean, args);
                        //3.輸出結(jié)束時間
                        System.out.println("方法:"+method.getName()+"-結(jié)束時間:"+new Date());
                        return invoke;
                    }
                }
        );
        return beanProxy;
    }
}

2.在xml文件上完成對TimeLogBeanPostProcessor類的配置

<bean class="com.tangyuan.processor.TimeLogBeanPostProcessor"></bean>

3.編寫方法

package com.tangyuan.dao;
public interface UserDao {
    void show();
}
package com.tangyuan.dao.impl;
import com.tangyuan.dao.UserDao;
import org.springframework.beans.factory.InitializingBean;
public class UserDaoImpl implements UserDao , InitializingBean {
    public UserDaoImpl() {
        System.out.println("UserDao實例化");
    }
    public void init(){
        System.out.println("init初始化方法執(zhí)行");
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("屬性設(shè)置之后執(zhí)行~~~~");
    }
    @Override
    public void show() {//ctrl+Alt+t
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("show.....");
    }
}

4.測試

//創(chuàng)建ApplicationContext,加載配置文件,實例化容器
ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao dao = (UserDao) applicationContext.getBean("userDao");
dao.show();
方法:show-開始時間:Tue Nov 29 10:21:31 GMT+08:00 2022
show.....
方法:show-結(jié)束時間:Tue Nov 29 10:21:31 GMT+08:00 2022

四、Spring ioc整體流程總結(jié)

到此這篇關(guān)于Spring后處理器詳細(xì)介紹的文章就介紹到這了,更多相關(guān)Spring后處理器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 使用RequestBodyAdvice實現(xiàn)對Http請求非法字符過濾

    使用RequestBodyAdvice實現(xiàn)對Http請求非法字符過濾

    這篇文章主要介紹了使用RequestBodyAdvice實現(xiàn)對Http請求非法字符過濾的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Java-Java5.0注解全面解讀

    Java-Java5.0注解全面解讀

    這篇文章主要介紹了Java-Java5.0注解全面解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 詳解hibernate雙向多對多關(guān)聯(lián)映射XML與注解版

    詳解hibernate雙向多對多關(guān)聯(lián)映射XML與注解版

    本篇文章主要介紹了詳解hibernate雙向多對多關(guān)聯(lián)映射XML與注解版,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • 一文帶你深入了解Java中延時任務(wù)的實現(xiàn)

    一文帶你深入了解Java中延時任務(wù)的實現(xiàn)

    延時任務(wù)相信大家都不陌生,在現(xiàn)實的業(yè)務(wù)中應(yīng)用場景可以說是比比皆是。這篇文章主要為大家介紹幾種實現(xiàn)延時任務(wù)的辦法,感興趣的可以了解一下
    2022-11-11
  • Java多線程之CAS算法實現(xiàn)線程安全

    Java多線程之CAS算法實現(xiàn)線程安全

    這篇文章主要介紹了java中如何通過CAS算法實現(xiàn)線程安全,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,下面小編和大家一起來學(xué)習(xí)一下吧
    2019-05-05
  • Java泛型的繼承和實現(xiàn)操作示例

    Java泛型的繼承和實現(xiàn)操作示例

    這篇文章主要介紹了Java泛型的繼承和實現(xiàn)操作,結(jié)合實例形式分析了java泛型類的繼承以及泛型接口的實現(xiàn)相關(guān)操作技巧,需要的朋友可以參考下
    2019-08-08
  • Java利用Geotools實現(xiàn)不同坐標(biāo)系之間坐標(biāo)轉(zhuǎn)換

    Java利用Geotools實現(xiàn)不同坐標(biāo)系之間坐標(biāo)轉(zhuǎn)換

    GeoTools 是一個開源的 Java GIS 工具包,可利用它來開發(fā)符合標(biāo)準(zhǔn)的地理信息系統(tǒng)。本文將利用工具包Geotools實現(xiàn)不同坐標(biāo)系之間坐標(biāo)轉(zhuǎn)換,感興趣的可以了解一下
    2022-08-08
  • Struts2學(xué)習(xí)手冊之文件上傳基礎(chǔ)教程

    Struts2學(xué)習(xí)手冊之文件上傳基礎(chǔ)教程

    Struts2提供的文件上傳下載機制十分簡便,使得我們寫很少的代碼,下面這篇文章主要給大家介紹了關(guān)于Struts2學(xué)習(xí)手冊之文件上傳的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2018-05-05
  • SpringBoot整合EasyExcel進行大數(shù)據(jù)處理的方法詳解

    SpringBoot整合EasyExcel進行大數(shù)據(jù)處理的方法詳解

    EasyExcel是一個基于Java的簡單、省內(nèi)存的讀寫Excel的開源項目。在盡可能節(jié)約內(nèi)存的情況下支持讀寫百M的Excel。本文將在SpringBoot中整合EasyExcel進行大數(shù)據(jù)處理,感興趣的可以了解一下
    2022-05-05
  • Fluent Mybatis快速入門詳細(xì)教程

    Fluent Mybatis快速入門詳細(xì)教程

    由于FluentMybatis是基于mybatis上做封裝和擴展的,所以這里主要聊聊mybatis處理的方式,以及給出FluentMybatis的解放方案。對Fluent Mybatis入門相關(guān)知識感興趣的朋友一起看看吧
    2021-08-08

最新評論