成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

模仿 Spring 實(shí)現(xiàn)一個(gè)類管理容器

網(wǎng)絡(luò)
項(xiàng)目的初衷是獨(dú)立作出一個(gè)成熟的有特色的IOC容器,但由于過(guò)程參考Spring太多,而且也無(wú)法作出太多改進(jìn),于是目的變?yōu)橐源隧?xiàng)目作為理解Spring的一個(gè)跳板,與網(wǎng)上的一些模仿Spring的框架不同,本項(xiàng)目主要是針對(duì)注解形式 地址是Thales

概述

項(xiàng)目的初衷是獨(dú)立作出一個(gè)成熟的有特色的IOC容器,但由于過(guò)程參考Spring太多,而且也無(wú)法作出太多改進(jìn),于是目的變?yōu)橐源隧?xiàng)目作為理解Spring的一個(gè)跳板,與網(wǎng)上的一些模仿Spring的框架不同,本項(xiàng)目主要是針對(duì)注解形式
地址是Thales

流程

在Spring中,一個(gè)bean的形成分三個(gè)大的階段,

bean的定義階段(包含BeanDefinition的加載,解析,與注冊(cè))
bean的實(shí)例化階段(包含對(duì)象的創(chuàng)建,屬性的注入)
bean的初始化階段(包含一些資源的初始化,譬如打開(kāi)文件建立連接等等)
這只是大概的劃分,關(guān)于BeanPostProcessor等后置處理并沒(méi)有顯式的提及.

類的設(shè)計(jì)

如果只想了解一個(gè)bean是怎么從生到死的,只需要一步步debug就好了,如果看不懂,就多debug幾遍.可是如果想實(shí)現(xiàn)一個(gè)類似的容器,類的設(shè)計(jì),職責(zé)的分配,接口的實(shí)現(xiàn)繼承必然是要了解的(除非你想幾個(gè)類做完所有的事)

以下是DefaultListableBeanFactory的類圖

是不是頂不住

我們?cè)賮?lái)看一張圖

第一張是Spring5.0的,第二張圖是Spring0.9的,所以并沒(méi)有必要在一開(kāi)始就引入過(guò)多的設(shè)計(jì)復(fù)雜度

我們?cè)賮?lái)看一套對(duì)比圖

哪一個(gè)是0.9的,哪一個(gè)是5.0的一目了然.

說(shuō)這么多的目的,是說(shuō)明我們沒(méi)必要一開(kāi)始就奔著最完善的目標(biāo)去寫(xiě),可以一步步來(lái),一步步加入功能

實(shí)現(xiàn)簡(jiǎn)易IOC
眾所周知,SpringIoC中最基本的就是BeanFactory

我們先定義一個(gè)BeanFactory接口

  1. //暫時(shí)就給這一個(gè)方法public interface BeanFactory {    /**     * 根據(jù)名字獲取Bean實(shí)例     * @param name     * @return     */    Object getBean(String name);} 

beanDefinition

由于是注解形式,我們不能再像xml那樣給定一個(gè)資源文件再去解析了,而應(yīng)該去掃描classPath下所有帶有@Component的類,

這時(shí)候我們需要給定的參數(shù)就從文件路徑變成了包路徑,我們只需要掃描這個(gè)包及其子包內(nèi)符合條件的類,并且將其轉(zhuǎn)化為BeanDefinition再注冊(cè)就好.執(zhí)行這個(gè)功能的是ClassPathBeanDefinitionScanner這個(gè)類.在這一步,就已經(jīng)和傳統(tǒng)的流程有所區(qū)別了,我們會(huì)傳入一個(gè)ResourceLoader去實(shí)現(xiàn)具體的掃描功能(即定位),但不會(huì)再有專門的類去處理解析這一步

  1. public interface Resource {    File getFile();    String getFilename();    String getFilePath();}//在最初設(shè)計(jì)的時(shí)候這個(gè)抽象類似乎沒(méi)有用,但考慮到以后的擴(kuò)展,還是先放在這public abstract class AbstractResource implements Resource {    @Override    public String getFilename() {        return getFile().getName();    }    @Override    public String getFilePath() {        return getFile().getPath();    }}//這就是最終我們實(shí)例化bean時(shí)用到的Resource類,在Spring中并沒(méi)有直接用,而是通過(guò)外觀模式集成了一下成為RootBeanDefinitionpublic class ClassPathResource extends AbstractResource {    private final String path;    private ClassLoader classLoader;    private Class<?> clazz;    public ClassPathResource(String path, ClassLoader classLoader, Class<?> clazz) {        this.path = path;        this.classLoader = classLoader;        this.clazz = clazz;    }} 

  1. public interface ResourceLoader {    Resource getResource(String location);}//此類能夠?qū)崿F(xiàn)加載多個(gè)資源public interface ResourcePatternResolver extends ResourceLoader {    String CLASSPATH_ALL_URL_PREFIX = "classpath*:";    List<? extends Resource> getResources(String location);}//這個(gè)類就是正式用于掃描的類了public class PathMatchingResourcePatternResolver implements ResourcePatternResolver {    private final ResourceLoader resourceLoader;    public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader){        this.resourceLoader = resourceLoader;    }    @Override    public Resource getResource(String location) {        return resourceLoader.getResource(location);    }//在Spring中,是通過(guò)一層層方法的包裝完成包名到路徑的轉(zhuǎn)換再到每個(gè)文件的掃描再轉(zhuǎn)換為Resource,這里暫時(shí)就先一步到位,把具體實(shí)現(xiàn)放在工具類里    @Override    public List<? extends Resource> getResources(String location) {        Set<Class<?>> classes = ClassUtils.getClasses(location);        List<ClassPathResource> classPathResources = new ArrayList<>();        for (Class<?> clazz:classes) {            classPathResources.add(new ClassPathResource("",clazz.getClassLoader(),clazz));        }        return classPathResources;    }} 

但最后直接使用的并不是PathMatchingResourcePatternResolver

而是把他作為ClassPathBeanDefinitionScanner的一個(gè)屬性,在這個(gè)類里調(diào)用.

我們得到了Resource,如何獲得對(duì)應(yīng)的BeanDefinition?

先考慮這樣一個(gè)問(wèn)題,什么樣的類可以被注冊(cè)BeanDefinition?

添加了@Component注解或者滿足其他注冊(cè)的條件
不是接口或者抽象類
所以我們可以單獨(dú)抽象出一個(gè)方法 boolean isCandidateComponent(Class<?> clazz)來(lái)判斷是否被注冊(cè)

現(xiàn)在到了注冊(cè)階段,依舊秉持面向接口編程的理念,同時(shí)考慮到單一職責(zé),我們把注冊(cè)Bean定義單獨(dú)抽象出來(lái)

  1. public interface BeanDefinitionRegistry {    void registerBeanDefinition(BeanDefinition beanDefinition);} 

上文說(shuō)到Bean定義的定位,解析,注冊(cè)都是在ClassPathBeanDefinitionScanner里完成的,于是BeanDefinitionRegistry自然也成為了ClassPathBeanDefinitionScanner的屬性之一

于是ClassPathBeanDefinitionScanner構(gòu)建完成了

  1. public class ClassPathBeanDefinitionScanner {    //負(fù)責(zé)具體的Resource定位    private ResourcePatternResolver resourcePatternResolver;    //負(fù)責(zé)BeanDefinition解析    private BeanDefinitionRegistry registry;    public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry,String...basePackage) {        this.registry = registry;        this.resourcePatternResolver = new PathMatchingResourcePatternResolver((ResourceLoader) registry);        this.scan(basePackage);    }    public void scan(String...basePackages){        doScan(basePackages);    }    void doScan(String[] basePackages){        Set<BeanDefinition> beanDefinitions = new LinkedHashSet<>();        for (String basePackage:basePackages) {            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);            for(BeanDefinition candidate:candidates){                beanDefinitions.add(candidate);                registry.registerBeanDefinition(candidate);            }        }    }    //獲取被注冊(cè)的bean的集合    private Set<BeanDefinition> findCandidateComponents(String basePackage) {        Set<BeanDefinition> candidates = new LinkedHashSet<>();        List<? extends Resource> resources = getResourcePatternResolver().getResources(basePackage);        for(Resource resource:resources){            if(resource instanceof ClassPathResource){                ClassPathResource classPathResource = (ClassPathResource)resource;                if(isCandidateComponent(classPathResource.getClazz())){                    AnnotationBeanDefinition beanDefinition = new AnnotationBeanDefinition();                    beanDefinition.setClazz(classPathResource.getClazz());                    beanDefinition.setBeanName(BeanUtils.generateBeanName(classPathResource.getClazz().getName()));                    candidates.add(beanDefinition);                }            }        }        return candidates;    }    private ResourcePatternResolver getResourcePatternResolver() {        return this.resourcePatternResolver;    }    //判斷是否被注冊(cè)    boolean isCandidateComponent(Class<?> clazz){        Component declaredAnnotation = clazz.getDeclaredAnnotation(Component.class);        return declaredAnnotation!=null&&!clazz.isInterface();    }    ;} 

實(shí)例化

在什么時(shí)候?qū)嵗?我們說(shuō),在調(diào)用getBean()而又沒(méi)有現(xiàn)成的bean時(shí)進(jìn)行實(shí)例化

  1. public abstract class AbstractBeanFactory implements BeanFactory{    @Override    public Object getBean(String beanName)    } 

對(duì)象創(chuàng)建

有兩種方式,通過(guò)Jdk默認(rèn)的反射實(shí)現(xiàn),或者用cglib代理實(shí)現(xiàn).

默認(rèn)自然是無(wú)參構(gòu)造,但是如果傳入了參數(shù),則需要根據(jù)參數(shù)的類型和數(shù)量去匹配對(duì)應(yīng)的構(gòu)造函數(shù),用其去實(shí)例化

于是我們抽象出InstantiationStrategy作為實(shí)例化接口,兩種實(shí)例化方法都需要實(shí)現(xiàn)這個(gè)接口,我們真正去用的時(shí)候只需要去調(diào)該接口的方法就好

  1. public interface InstantiationStrategy {    Object instantiate(BeanDefinition beanDefinition, String beanName, BeanFactory owner);}public class SimpleInstantiationStrategy implements InstantiationStrategy {} 

屬性注入

字段值獲取

有兩種方式可以實(shí)現(xiàn)字段值獲取

直接注解Autowired或者Value
Value里面填的不是值而是占位符,那么就需要解析占位符去獲取
我們通過(guò)Class對(duì)象獲取所有字段,再通過(guò)遍歷所有字段查找加在字段上的注解來(lái)獲取(這僅僅只是Spring的一種注入方式)

  1. //處理@Autowired注解        for(Field field:declaredFields){            Autowired autowired = field.getDeclaredAnnotation(Autowired.class);            if(autowired != null){                pvs.add(new PropertyValue(field.getName(),new BeanReference(BeanUtils.generateBeanName(field.getType().getName()),field.getType())));            }        }        //處理@Value注解        for(Field field:declaredFields){            Value value = field.getDeclaredAnnotation(Value.class);            if(value != null){                String value1 = value.value();                pvs.add(new PropertyValue(field.getName(),value1));            }        } 

字段值填充

獲取字段值后通過(guò)反射填入相應(yīng)的字段中

  1. for(Field field:mbd.getBeanClass().getDeclaredFields()){                field.setAccessible(true);                if (field.getName().equals(propertiesValue.getName())&&field.getType().isAssignableFrom(newValue.getClass())) {                    field.set(bean,newValue);                }            } 

初始化

調(diào)用指定的初始化方法,進(jìn)行資源的初始化.,如何獲取初始化方法?在xml模式中,只要加個(gè)標(biāo)簽即可,如果是注解模式,加個(gè)注解標(biāo)識(shí)一下或者在某個(gè)注解上加個(gè)參數(shù),代表初始化方法,這個(gè)還沒(méi)有實(shí)現(xiàn)

功能填充

后置處理器添加

上面我們已經(jīng)實(shí)現(xiàn)了一個(gè)可以進(jìn)行依賴查找,依賴注入的Bean容器,讓我們?cè)倩仡櫼幌耂pring的流程,我們少了些什么,最容易想到的應(yīng)該就是后置處理器了,包括BeanFactoryPostProcessor和BeanPostProcessor兩種,前者對(duì)于beanFactory進(jìn)行修改操作,后者對(duì)于bean進(jìn)行修改操作,同樣是面向接口編程

首先建立BeanPostProcessor

  1. public interface BeanPostProcessor {       Object postProcessBeforeInitialization(Object bean, String beanName);    Object postProcessAfterInitialization(Object bean, String beanName) ;} 

就目前來(lái)看,有什么是需要BeanPostProcessor來(lái)做的呢?我們可以把之前對(duì)注解進(jìn)行處理,獲取注入屬性的代碼分離出來(lái),專門用一個(gè)BeanPostProcessor去處理

所有自定義實(shí)現(xiàn)的BeanPostProcessor都需要繼承這個(gè)接口,由于BeanPostProcessor的作用是處理其他的Bean,所以必須要在其他被處理的Bean實(shí)例化之前被創(chuàng)建出來(lái).于是我們?cè)趂inishBeanFactoryInitialization(beanFactory);之前添加registerBeanPostProcessors(beanFactory);用于實(shí)例化所有的BeanPostProcessor

而這些beanPostProcessor的重要程度是不同的,例如處理注解注入的BeanPostProcessor優(yōu)先級(jí)就要比一般的BeanPostProcessor優(yōu)先級(jí)要高,所以需要先實(shí)例化

Aware接口添加

其實(shí)現(xiàn)在我們已經(jīng)可以完全的把一個(gè)對(duì)象交由IOC容器了,但此時(shí)這個(gè)對(duì)象與容器之間的關(guān)系是單向的,容器能夠操作bean,但bean不能借助容器,為了解決此類問(wèn)題,我們添加一個(gè)Aware接口作為標(biāo)志接口,由各個(gè)更具體的Aware去繼承他,并在實(shí)例化屬性之后,初始化方法執(zhí)行之完成相關(guān)容器屬性的注入

事件監(jiān)聽(tīng)器添加

監(jiān)聽(tīng)器是觀察者模式的一種實(shí)現(xiàn)

我們先定義以下幾個(gè)基本接口

  1. public interface ApplicationEventPublisher {    /**     * 發(fā)布事件     * @param event     */    void publishEvent(ApplicationEvent event);}public interface ApplicationEventMulticaster {    /**     * 添加廣播事件     * @param event     */    void multicastEvent(ApplicationEvent event);    /**     * 添加對(duì)于某個(gè)事件的監(jiān)聽(tīng)器     * @param listener     */    void addApplicationListener(ApplicationListener listener);    /**     * 移除指定監(jiān)聽(tīng)器     * @param listener     */    void removeApplicationListener(ApplicationListener listener);}public interface ApplicationListener <E extends ApplicationEvent> extends EventListener {    /**     * 監(jiān)聽(tīng)特定事件     * @param event     */    void onApplicationEvent(E event);} 

具體調(diào)用流程為具體的listener被添加到廣播器中,事件通過(guò)publisher統(tǒng)一發(fā)布,而publishEvent最后會(huì)調(diào)用 multicastEvent(ApplicationEvent event)方法,經(jīng)過(guò)相應(yīng)判斷后由對(duì)應(yīng)監(jiān)聽(tīng)器做出相應(yīng)操作.

如何判斷這個(gè)監(jiān)聽(tīng)器是否對(duì)該事件感興趣?

我們事先實(shí)現(xiàn)的listener是有泛型的,我們可以通過(guò)這個(gè)泛型與傳入的事件類型的關(guān)系來(lái)判斷

  1. public boolean supportEvent(ApplicationListener<ApplicationEvent> listener,ApplicationEvent event){        //先獲取Class對(duì)象        Class<? extends ApplicationListener> listenerClass = listener.getClass();        //獲取其實(shí)現(xiàn)的所有接口(包括泛型信息)        Type[] genericInterfaces = listenerClass.getGenericInterfaces();        for (Type genericInterface:genericInterfaces){            //判斷是否為泛型接口            if(genericInterface instanceof ParameterizedType){                ParameterizedType parameterizedType = (ParameterizedType) genericInterface;                //得到所有泛型參數(shù)                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();                for(Type actualTypeArgument:actualTypeArguments){                    try {                        Class<?> aClass = Class.forName(actualTypeArgument.getTypeName());                        //判斷感興趣的事件類型是否與傳入事件相同,或者是其父類                        if(aClass.isAssignableFrom(event.getClass())){                            return true;                        }                    } catch (ClassNotFoundException e) {                        e.printStackTrace();                    }                }            }        }        return false;    } 

FactoryBean添加

目前的Bean都是由BeanFactory來(lái)產(chǎn)生的,

我們用FactoryBean接口來(lái)標(biāo)識(shí)這個(gè)產(chǎn)生Bean的特殊的Bean

循環(huán)依賴的解決

循環(huán)依賴是指A依賴于B的同時(shí)B依賴于A,解決方法為實(shí)例化與初始化分離,如果只考慮一般情況的話用兩級(jí)緩存實(shí)際上就夠了,

代碼優(yōu)化

實(shí)現(xiàn)簡(jiǎn)易AOP

如果從正統(tǒng)的AOP開(kāi)始的話,隨之而來(lái)的就是一堆概念,包括切點(diǎn),通知一類

我們先看AOP要做什么

所以說(shuō)AOP的核心就是動(dòng)態(tài)代理,我們以Cglib為例來(lái)看看動(dòng)態(tài)代理要怎么用

  1. Enhancer enhancer = new Enhancer();//1. 為哪個(gè)類進(jìn)行代理        enhancer.setSuperclass(Buy.class);        enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {            //2. 為該類的哪個(gè)方法進(jìn)行代理            if(method.getName().equals("buyOne")){                //3. 代理究竟要做什么                System.out.println("hello");            }            //4. 調(diào)用原有的對(duì)象             methodProxy.invokeSuper(o,objects);                     return o;        });//5. 產(chǎn)生代理后的對(duì)象        Buy o = (Buy)enhancer.create(); 

這就是動(dòng)態(tài)代理最核心的功能,也是AOP的核心功能,AOP的最終目的是代碼5,即產(chǎn)生一個(gè)代理對(duì)象,把這個(gè)代理對(duì)象交給IOC去管理

而為了達(dá)成這個(gè)目的,AOP框架需要做好代碼1-4所需要做的事,一和二組合起來(lái),成了JoinPoint,3叫做Advice,這兩個(gè)組合起來(lái)就叫做Advisor,可不可以不分這些種類,就全寫(xiě)在一個(gè)或幾個(gè)類里,當(dāng)然可以,Spring0.9就是這么做的,但發(fā)展到如今,早已采用了這種劃分方式.本項(xiàng)目也采用這種分類.

先從連接點(diǎn)說(shuō)起,如何確定到底在哪里實(shí)現(xiàn)功能增強(qiáng),無(wú)非是類與方法兩個(gè)層次;

我們先定義ClassFilter與MethodMacther兩個(gè)接口

  1. public interface ClassFilter {    /**     * 給定類型是否匹配     * @param clazz     * @return     */    boolean matches(Class< ? > clazz);}public interface MethodMatcher {    /**     * 對(duì)應(yīng)類的對(duì)應(yīng)方法是否匹配     * @param method     * @param targetClass     * @return     */    boolean matches(Method method,Class< ? > targetClass);} 

這兩個(gè)接口必然是組合起來(lái)使用的,于是我們用PointCut將其組合起來(lái)

  1. public interface Pointcut {    /**     * 獲取ClassFilter     * @return     */    ClassFilter getClassFilter();    /**     * 獲取MethodMatcher     * @return     */    MethodMatcher getMethodMatcher();} 

接口只是定義了抽象功能,這些功能還要有具體的實(shí)現(xiàn)

我們默認(rèn)用Java的正則去匹配方法名,以此構(gòu)建出JdkRegexMethodMatcher

  1. public class JdkRegexMethodPointcut implements MethodMatcher, Pointcut{    private Pattern[] compiledPatterns = new Pattern[0];    @Override    public ClassFilter getClassFilter() {        return null;    }    @Override    public MethodMatcher getMethodMatcher() {        return this;    }    @Override    public boolean matches(Method method, Class<?> targetClass) {        String name = method.getName();        for (Pattern pattern :compiledPatterns) {            Matcher matcher = pattern.matcher(name);            if(matcher.matches()){                return true;            }        }        return false;    }    //預(yù)編譯    private Pattern[] compilePatterns(String[] source) throws PatternSyntaxException {        Pattern[] destination = new Pattern[source.length];        for (int i = 0; i < source.length; i++) {            destination[i] = Pattern.compile(source[i]);        }        return destination;    }    public void initPatternRepresentation(String[] patterns) throws PatternSyntaxException {        this.compiledPatterns = compilePatterns(patterns);    }} 

在Spring中,并不是直接繼承的MethodMatcher,考慮到正則的語(yǔ)法不同,額外做了一層抽象,但在此處省略掉了

而JdkRegexMethodMatcher同時(shí)也實(shí)現(xiàn)了PointCut類,也就是說(shuō),現(xiàn)在切點(diǎn)已經(jīng)準(zhǔn)備好了

再來(lái)看Advice

由于考慮的可擴(kuò)展點(diǎn)比較多,于是繼承的層次也變的多了

  1. public interface Advice {}public interface BeforeAdvice extends Advice{}public interface MethodBeforeAdvice extends BeforeAdvice{        void before(Method method, Object[] args, Object target) throws Throwable;} 

現(xiàn)在Advice也定義完了,具體的實(shí)現(xiàn)我們交由用戶去做

接下來(lái)就是整合成Advisor了

  1. public interface Advisor {    Advice getAdvice();}public interface PointcutAdvisor extends Advisor{       Pointcut getPointcut();}public abstract class AbstractPointcutAdvisor implements PointcutAdvisor{    private Advice advice;    @Override    public Advice getAdvice() {        return advice;    }    public void setAdvice(Advice advice) {        this.advice = advice;    }} 

目前已經(jīng)定義好了Advisor的功能

我們?cè)賹?shí)現(xiàn)這個(gè)接口

  1. public class RegexMethodPointcutAdvisor extends AbstractPointcutAdvisor {    JdkRegexMethodPointcut pointcut = new JdkRegexMethodPointcut();    private String[] patterns;    public RegexMethodPointcutAdvisor() {    }    public RegexMethodPointcutAdvisor(Advice advice) {        setAdvice(advice);    }    public void setPattern(String pattern) {        setPatterns(pattern);    }    public void setPatterns(String... patterns) {        this.patterns = patterns;        pointcut.initPatternRepresentation(patterns);    }    @Override    public Pointcut getPointcut() {        return pointcut;    }} 

RegexMethodPointcutAdvisor就整合了PointCut以及Advice,通過(guò)他,我們就可以確定在何處做何種增強(qiáng).

現(xiàn)在的advisor可以完成檢驗(yàn)一個(gè)類是否要被代理的功能,但是如果這個(gè)類需要被代理,advisor卻無(wú)法保存這個(gè)類的對(duì)應(yīng)信息

于是我們需要一個(gè)類將advisor與對(duì)應(yīng)的代理類結(jié)合起來(lái),這就是AdvisedSupport

  1. public class AdvisedSupport {    private  TargetSource targetSource;    private List<MethodInterceptor> methodInterceptors = new ArrayList<>();    private List<PointcutAdvisor> advisors = new ArrayList<>();    public TargetSource getTargetSource() {        return targetSource;    }    public void setTargetSource(TargetSource targetSource) {        this.targetSource = targetSource;    }    public List<MethodInterceptor> getMethodInterceptor() {        return methodInterceptors;    }    public void addMethodInterceptor(MethodInterceptor methodInterceptor) {        this.methodInterceptors.add(methodInterceptor);    }    public List<PointcutAdvisor> getAdvisor() {        return advisors;    }    public void addAdvisor(PointcutAdvisor advisor) {        MethodBeforeAdviceInterceptor methodBeforeAdviceInterceptor = new MethodBeforeAdviceInterceptor();        methodBeforeAdviceInterceptor.setAdvice((MethodBeforeAdvice) advisor.getAdvice());        addMethodInterceptor(methodBeforeAdviceInterceptor);        this.advisors.add(advisor);    }} 

上類屬性中的TargetSource便是真正持有代理對(duì)象信息的類

現(xiàn)在萬(wàn)事具備,只需要用Cglib去使用我們已經(jīng)持有的信息就可以創(chuàng)建出新的類了

  1. public class CglibAopProxy implements AopProxy{    private final AdvisedSupport advised;    public CglibAopProxy(AdvisedSupport advised) {        this.advised = advised;    }    @Override    public Object getProxy() {        Enhancer enhancer = new Enhancer();        //1. 為哪個(gè)類進(jìn)行代理        enhancer.setSuperclass(advised.getTargetSource().getTargetClass());        enhancer.setCallback(new DynamicAdvisedInterceptor(advised));        //5. 產(chǎn)生代理后的對(duì)象        return enhancer.create();    }    private static class DynamicAdvisedInterceptor implements MethodInterceptor {        private final AdvisedSupport advised;        public DynamicAdvisedInterceptor(AdvisedSupport advised) {            this.advised = advised;        }        @Override        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {            CglibInvocation cglibInvocation = new CglibInvocation(method,objects,o,methodProxy);            //2. 為該類的哪個(gè)方法進(jìn)行代理            for(PointcutAdvisor advisor: advised.getAdvisor()){                if(advisor.getPointcut().getMethodMatcher().matches(method,advised.getTargetSource().getTargetClass())){                    //3. 代理究竟要做什么                    return advised.getMethodInterceptor().get(0).invoke(cglibInvocation);                }            }            //4. 調(diào)用源方法            return cglibInvocation.proceed();        }    }} 

將這份代碼與最初使用cglib的代碼比較,會(huì)發(fā)現(xiàn)過(guò)程幾乎是一模一樣.但是作為一個(gè)框架,應(yīng)該盡可能的給用戶以方便

于是我們需要一個(gè)Creator去把這一切都做好,他需要負(fù)責(zé)將Advice和PointCut組合成Advisor,再將Advisor與TargetSource組裝成AdvisedSupport,再將AdvisedSupport交給Cglib動(dòng)態(tài)代理,產(chǎn)生代理對(duì)象,而用戶只需要編寫(xiě)Advice以及切入點(diǎn)表達(dá)式即可

功能演示

屬性注入基本類型引用類型循環(huán)依賴
容器感知
FactoryBean生成對(duì)象
AOP切面增強(qiáng)
自定義BeanPostProcessor

困難及解決

首先是設(shè)計(jì)上的問(wèn)題
FactoryBean的實(shí)現(xiàn)
AOP與IOC的結(jié)合
字段的注入

責(zé)任編輯:梁菲 來(lái)源: 阿里云云棲號(hào)
相關(guān)推薦

2021-02-17 09:39:41

PodmanDockerLinux

2011-03-24 09:34:41

SPRING

2015-12-30 14:50:45

Kubernetes容器技術(shù)Docker

2022-09-22 16:21:43

開(kāi)源GUI 應(yīng)用

2019-01-11 13:57:06

2023-11-28 13:50:00

Kubernetes容器

2025-01-03 09:00:00

代碼C++gTest

2021-05-20 07:56:35

Bean容器Spring

2019-12-09 15:00:48

TomcatServlet容器

2025-03-21 08:30:00

容器管理開(kāi)發(fā)開(kāi)源

2023-05-15 13:59:53

紅帽容器原生虛擬化KubeVirt

2019-04-09 08:50:15

Rancher容器運(yùn)維

2013-07-02 10:24:52

團(tuán)隊(duì)管理團(tuán)隊(duì)遠(yuǎn)程團(tuán)隊(duì)

2020-11-13 07:08:51

Spring Boot應(yīng)用Spring

2023-10-18 15:25:29

數(shù)據(jù)源數(shù)據(jù)庫(kù)

2022-01-26 15:20:00

配置微服務(wù)架構(gòu)

2020-09-24 11:46:03

Promise

2022-08-02 14:21:20

滑動(dòng)驗(yàn)證碼鴻蒙

2022-07-13 15:31:29

手繪板canvas鴻蒙

2022-07-28 14:20:44

懸浮球鴻蒙
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 成人三级av| 欧美日产国产成人免费图片 | 精品九九在线 | 精品在线一区 | 久久国产精品视频 | 欧美大片一区 | 久久久久成人精品亚洲国产 | 欧美日韩久久精品 | 亚洲高清一区二区三区 | 日韩欧美在线观看视频 | 麻豆changesxxx国产 | 免费观看的黄色网址 | 国产一区二区三区在线看 | 国产成人综合在线 | 国产精品精品久久久久久 | 欧美综合一区二区三区 | 国产精品国产成人国产三级 | 欧美亚洲视频 | 日日噜噜噜夜夜爽爽狠狠视频, | 久久美国 | 欧美日韩综合 | 深夜福利影院 | 国产一区免费视频 | 欧美区在线观看 | 久久综合成人精品亚洲另类欧美 | 暖暖成人免费视频 | 成人久久久久久久久 | www国产亚洲精品久久网站 | 日韩高清一区二区 | 色综合天天天天做夜夜夜夜做 | 国产精品99久久久久久宅男 | 亚洲手机视频在线 | 久久久亚洲一区 | 成人教育av | 精品一区二区三区在线观看国产 | 国产在线精品一区二区 | 午夜丁香视频在线观看 | 91精品久久久久久久久中文字幕 | 国产久 | 草久在线| 久久青|