手写Spring:第13章-把AOP扩展到Bean的生命周期

文章目录

  • 一、目标:把AOP扩展到Bean的生命周期
  • 二、设计:把AOP扩展到Bean的生命周期
  • 三、实现:把AOP扩展到Bean的生命周期
    • [3.1 工程结构](#3.1 工程结构)
    • [3.2 AOP动态代理融入Bean的生命周期类图](#3.2 AOP动态代理融入Bean的生命周期类图)
    • [3.3 定义Advice拦截器链](#3.3 定义Advice拦截器链)
      • [3.3.1 定义拦截器链接口](#3.3.1 定义拦截器链接口)
      • [3.3.2 方法拦截器链接口](#3.3.2 方法拦截器链接口)
    • [3.4 定义Advisor访问者](#3.4 定义Advisor访问者)
      • [3.4.1 定义拦截器访问者接口](#3.4.1 定义拦截器访问者接口)
      • [3.4.2 定义切面拦截器访问者](#3.4.2 定义切面拦截器访问者)
      • [3.4.3 切面访问者实现类](#3.4.3 切面访问者实现类)
      • [3.4.4 方法拦截器](#3.4.4 方法拦截器)
    • [3.5 代理工厂](#3.5 代理工厂)
      • [3.5.1 切面添加代理配置](#3.5.1 切面添加代理配置)
      • [3.5.2 定义代理工厂](#3.5.2 定义代理工厂)
    • [3.6 融入Bean生命周期的自动代理创建者](#3.6 融入Bean生命周期的自动代理创建者)
      • [3.6.1 实例化感知对象处理](#3.6.1 实例化感知对象处理)
      • [3.6.2 默认自动代理创建者](#3.6.2 默认自动代理创建者)
    • [3.7 融入到Bean的生命周期](#3.7 融入到Bean的生命周期)
  • 四、测试:把AOP扩展到Bean的生命周期
    • [4.1 添加测试配置](#4.1 添加测试配置)
      • [4.1.1 用户自定义拦截方法](#4.1.1 用户自定义拦截方法)
      • [4.1.2 配置文件](#4.1.2 配置文件)
    • [4.2 单元测试](#4.2 单元测试)
      • [4.2.0 测试环境初始化](#4.2.0 测试环境初始化)
      • [4.2.1 前置拦截器测试](#4.2.1 前置拦截器测试)
      • [4.2.2 拦截器访问者测试](#4.2.2 拦截器访问者测试)
      • [4.2.3 单元测试](#4.2.3 单元测试)
  • 五、总结:把AOP扩展到Bean的生命周期

一、目标:把AOP扩展到Bean的生命周期

💡 如何完成AOP和Spring框架的整合?

  • 现在通过基于 Proxy.newProxyInstance 代理操作中处理方法匹配和方法拦截,对匹配的对象进行自定义的处理操作。
  • 并把这样的技术核心内容拆解到 Spring 中,用于实现 AOP 部分,通过拆分后基本可以明确各个类的职责,包括你的代理目标对象属性、拦截器属性、方法匹配属性,以及两种不同的代理操作 JDKCglib 的方式。
  • 在有了一个 AOP 核心功能的实现后,我们通过单元测试的方式进行验证切面功能对方法进行拦截,但如果这是一个面向用户使用的功能,就不太可能让用户这么复杂且没有与 Spring 结合的方式单独使用 AOP
  • 因此我们需要完成 AOP 核心功能和 Spring 框架的整合,最终能通过在 Spring 配置的方式完成切面的操作。

二、设计:把AOP扩展到Bean的生命周期

💡 怎么借着 BeanPostProcessor 把动态代理融入到 Bean 的生命周期中,以及如何组装各项切点、拦截、前置的功能和适配对应的代理器?

  • 为了可以让对象创建过程中,能把 xml 中配置的代理对象(切面)的一些类对象实例化,就需要用到 BeanPostProcessor 提供的方法。
    • 因为这个类中的方法可以分别作用与 Bean 对象执行初始化前后修改 Bean 的对象的扩展信息。
    • 但这里需要于 BeanPostProcessor 实现新的接口和实现类,这样才能定向获取对应的类信息。
  • 因为创建的代理对象不是流程里的普通对象,所以需要前置于其他对象的创建。
    • 实际开发中,需要在 AbstractAutowireCapableBeanFactory#createBean 优先完成 Bean 对象的判断,是否需要代理,有则直接返回代理对象。
  • 还需要解决方法拦截器的具体功能,提供一些 BeforeAdvice、AfterAdvice 的实现,让用户可以更简化的使用切面对象。
  • 除此以外还包括:需要包装切面表达式以及拦截方法的整合、提供不同类型的代理方式的代理工厂,来包装切面服务。

三、实现:把AOP扩展到Bean的生命周期

3.1 工程结构

java 复制代码
spring-step-12
|-src
	|-main
	|	|-java
	|		|-com.lino.springframework
	|			|-aop
	|			|	|-aspectj
	|			|	|	|-AspectJExpressionPointcut.java
	|			|	|	|-AspectJExpressionPointcutAdvisor.java
	|			|	|-framework
	|			|	|	|-adapter
	|			|	|	|	|-MethodBeforeAdviceInterceptor.java
	|			|	|	|-autoproxy
	|			|	|	|	|-DefaultAdvisorAutoProxyCreator.java
	|			|	|	|-AopProxy.java
	|			|	|	|-Cglib2AopProxy.java
	|			|	|	|-JdkDynamicAopProxy.java
	|			|	|	|-ProxyFactory.java
	|			|	|	|-ReflectiveMethodInvocation.java
	|			|	|-AdvisedSupport.java
	|			|	|-Advisor.java
	|			|	|-BeforeAdvice.java
	|			|	|-ClassFilter.java
	|			|	|-MethodBeforeAdvice.java
	|			|	|-MethodMatcher.java
	|			|	|-Pointcut.java
	|			|	|-PointcutAdvisor.java
	|			|	|-TargetSource.java
	|			|-beans
	|			|	|-factory
	|			|	|	|-config
	|			|	|	|	|-AutowireCapableBeanFactory.java
	|			|	|	|	|-BeanDefinition.java
	|			|	|	|	|-BeanFactoryPostProcessor.java
	|			|	|	|	|-BeanPostProcessor.java
	|			|	|	|	|-BeanReference.java
	|			|	|	|	|-ConfigurableBeanFactory.java
	|			|	|	|	|-InstantiationAwareBeanPostProcessor.java
	|			|	|	|	|-SingletonBeanRegistry.java
	|			|	|	|-support
	|			|	|	|	|-AbstractAutowireCapableBeanFactory.java
	|			|	|	|	|-AbstractBeabDefinitionReader.java
	|			|	|	|	|-AbstractBeabFactory.java
	|			|	|	|	|-BeabDefinitionReader.java
	|			|	|	|	|-BeanDefinitionRegistry.java
	|			|	|	|	|-CglibSubclassingInstantiationStrategy.java
	|			|	|	|	|-DefaultListableBeanFactory.java
	|			|	|	|	|-DefaultSingletonBeanRegistry.java
	|			|	|	|	|-DisposableBeanAdapter.java
	|			|	|	|	|-FactoryBeanRegistrySupport.java
	|			|	|	|	|-InstantiationStrategy.java
	|			|	|	|	|-SimpleInstantiationStrategy.java
	|			|	|	|-xml
	|			|	|	|	|-XMLBeanDefinitionReader.java
	|			|	|	|-Aware.java
	|			|	|	|-BeanClassLoaderAware.java
	|			|	|	|-BeanFactory.java
	|			|	|	|-BeanFactoryAware.java
	|			|	|	|-BeanNameAware.java
	|			|	|	|-ConfigurableListableBeanFactory.java
	|			|	|	|-DisposableBean.java
	|			|	|	|-FactoryBean.java
	|			|	|	|-HierarcgicalBeanFactory.java
	|			|	|	|-InitializingBean.java
	|			|	|	|-ListableBeanFactory.java
	|			|	|-BeansException.java
	|			|	|-PropertyValue.java
	|			|	|-PropertyValues.java
	|			|-context
	|			|	|-event
	|			|	|	|-AbstractApplicationEventMulticaster.java
	|			|	|	|-ApplicationContextEvent.java
	|			|	|	|-ApplicationEventMulticaster.java
	|			|	|	|-ContextclosedEvent.java
	|			|	|	|-ContextRefreshedEvent.java
	|			|	|	|-SimpleApplicationEventMulticaster.java
	|			|	|-support
	|			|	|	|-AbstractApplicationContext.java
	|			|	|	|-AbstractRefreshableApplicationContext.java
	|			|	|	|-AbstractXmlApplicationContext.java
	|			|	|	|-ApplicationContextAwareProcessor.java
	|			|	|	|-ClassPathXmlApplicationContext.java
	|			|	|-ApplicationContext.java
	|			|	|-ApplicationContextAware.java
	|			|	|-ApplicationEvent.java
	|			|	|-ApplicationEventPublisher.java
	|			|	|-ApplicationListener.java
	|			|	|-ConfigurableApplicationContext.java
	|			|-core.io
	|			|	|-ClassPathResource.java
	|			|	|-DefaultResourceLoader.java
	|			|	|-FileSystemResource.java
	|			|	|-Resource.java
	|			|	|-ResourceLoader.java
	|			|	|-UrlResource.java
	|			|-util
	|			|	|-ClassUtils.java
	|-test
		|-java
			|-com.lino.springframework.test
                |-bean
                |	|-IUserService.java
                |	|-UserService.java
                |	|-UserServiceBeforeAdvice.java
                |	|-UserServiceInterceptor.java
                |-ApiTest.java
		|-resources
			|-spring.xml

3.2 AOP动态代理融入Bean的生命周期类图

  • 整个类图看,在以 BeanPostProcessor 接口实现继承的 InstantiationAwareBeanPostProcessor 接口后,做了一个自动代理创建的类 DefaultAdvisorAutoProxyCreator,这个类就是用于处理整个 AOP 代理融入到 Bean 生命周期中的核心类。
  • DefaultAdvisorAutoProxyCreator 会依赖于拦截器、代理工厂和 PointcutAdvisor 的包装服务 AspectJExpressionPointcutAdvisor,由它提供切面、拦截方法和表达式。
  • Spring AOPAdvice 细化了 BeforeAdviceAfterAdviceAfterReturningAdviceThrowsAdvice

3.3 定义Advice拦截器链

3.3.1 定义拦截器链接口

BeforeAdvice.java

java 复制代码
package com.lino.springframework.aop;

import org.aopalliance.aop.Advice;

/**
 * @description: 拦截器链
 */
public interface BeforeAdvice extends Advice {
}

3.3.2 方法拦截器链接口

MethodBeforeAdvice.java

java 复制代码
package com.lino.springframework.aop;

import java.lang.reflect.Method;

/**
 * @description: 方法拦截器链
 */
public interface MethodBeforeAdvice extends BeforeAdvice {

    /**
     * 方法执行之前拦截
     *
     * @param method 方法
     * @param args   方法参数
     * @param target 目标对象
     * @throws Throwable 异常
     */
    void before(Method method, Object[] args, Object target) throws Throwable;
}
  • Spring 框架中,Advice 都是通过方法拦截器 MethodInterceptor 实现的。环绕 Advice 类似一个拦截器的链路,Before Advice、After Advice 等。

3.4 定义Advisor访问者

3.4.1 定义拦截器访问者接口

Advisor.java

java 复制代码
package com.lino.springframework.aop;

import org.aopalliance.aop.Advice;

/**
 * @description: 拦截器访问者
 */
public interface Advisor {

    /**
     * 获取拦截器
     *
     * @return 拦截器
     */
    Advice getAdvice();
}

3.4.2 定义切面拦截器访问者

PointcutAdvisor.java

java 复制代码
package com.lino.springframework.aop;

/**
 * @description: 切面拦截器访问者
 */
public interface PointcutAdvisor extends Advisor {

    /**
     * 获取切面
     *
     * @return 切面
     */
    Pointcut getPointcut();
}
  • PointcutAdvisor 承担了 PointcutAdvice 的组合。
    • Pointcut:用于获取 JoinPoint
    • Advice:决定 JoinPoint 执行什么操作。

3.4.3 切面访问者实现类

AspectJExpressionPointcutAdvisor.java

java 复制代码
package com.lino.springframework.aop.aspectj;

import com.lino.springframework.aop.Pointcut;
import com.lino.springframework.aop.PointcutAdvisor;
import org.aopalliance.aop.Advice;

/**
 * @description: 切面访问者实现类
 */
public class AspectJExpressionPointcutAdvisor implements PointcutAdvisor {

    /**
     * 切面
     */
    private AspectJExpressionPointcut pointcut;
    /**
     * 具体拦截方法
     */
    private Advice advice;
    /**
     * 表达式
     */
    private String expression;

    public void setExpression(String expression) {
        this.expression = expression;
    }

    @Override
    public Pointcut getPointcut() {
        if (null == pointcut) {
            pointcut = new AspectJExpressionPointcut(expression);
        }
        return pointcut;
    }

    @Override
    public Advice getAdvice() {
        return advice;
    }

    public void setAdvice(Advice advice) {
        this.advice = advice;
    }
}
  • AspectJExpressionPointcutAdvisor 实现了 PointcutAdvisor 接口,把切面 pointcut、拦截方法 advice 和具体的拦截表达式包装一起。
    • 这样就可以在 xml 的配置中定义一个 pointcutAdvisor 切面拦截器了。

3.4.4 方法拦截器

MethodBeforeAdviceInterceptor.java

java 复制代码
package com.lino.springframework.aop.framework.adapter;

import com.lino.springframework.aop.MethodBeforeAdvice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

/**
 * @description: 方法拦截器实现类
 */
public class MethodBeforeAdviceInterceptor implements MethodInterceptor {

    private MethodBeforeAdvice advice;

    public MethodBeforeAdviceInterceptor() {
    }

    public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
        this.advice = advice;
    }

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        this.advice.before(methodInvocation.getMethod(), methodInvocation.getArguments(), methodInvocation.getThis());
        return methodInvocation.proceed();
    }
}
  • MethodBeforeAdviceInterceptor 实现了 MethodInterceptor 接口,在 invoke 方法中调用 advice 中的 before 方法,传入对应的参数信息。
  • advice.before 则是用于自己实现 MethodBeforeAdvice 接口后做的相应处理。

3.5 代理工厂

3.5.1 切面添加代理配置

AdvisedSupport.java

java 复制代码
package com.lino.springframework.aop;

import org.aopalliance.intercept.MethodInterceptor;

/**
 * @description: 包装切面通知信息
 */
public class AdvisedSupport {
    /**
     * 代理配置
     */
    private boolean proxyTargetClass = false;
    /**
     * 被代理的目标对象
     */
    private TargetSource targetSource;
    /**
     * 方法拦截器
     */
    private MethodInterceptor methodInterceptor;
    /**
     * 方法匹配器(检查目标方法是否符合通知条件)
     */
    private MethodMatcher methodMatcher;

    public boolean isProxyTargetClass() {
        return proxyTargetClass;
    }

    public void setProxyTargetClass(boolean proxyTargetClass) {
        this.proxyTargetClass = proxyTargetClass;
    }

    public TargetSource getTargetSource() {
        return targetSource;
    }

    public void setTargetSource(TargetSource targetSource) {
        this.targetSource = targetSource;
    }

    public MethodInterceptor getMethodInterceptor() {
        return methodInterceptor;
    }

    public void setMethodInterceptor(MethodInterceptor methodInterceptor) {
        this.methodInterceptor = methodInterceptor;
    }

    public MethodMatcher getMethodMatcher() {
        return methodMatcher;
    }

    public void setMethodMatcher(MethodMatcher methodMatcher) {
        this.methodMatcher = methodMatcher;
    }
}

3.5.2 定义代理工厂

ProxyFactory.java

java 复制代码
package com.lino.springframework.aop.framework;

import com.lino.springframework.aop.AdvisedSupport;

/**
 * @description: 代理工厂
 */
public class ProxyFactory {

    private AdvisedSupport advisedSupport;

    public ProxyFactory(AdvisedSupport advisedSupport) {
        this.advisedSupport = advisedSupport;
    }

    public Object getProxy() {
        return createAopProxy().getProxy();
    }

    private AopProxy createAopProxy() {
        if (advisedSupport.isProxyTargetClass()) {
            return new Cglib2AopProxy(advisedSupport);
        }
        return new JdkDynamicAopProxy(advisedSupport);
    }
}
  • 代理工厂主要解决:关于 JDKCglib 两种代理的选择问题,有了代理工厂就可以按照不同的创建需求进行控制。

3.6 融入Bean生命周期的自动代理创建者

3.6.1 实例化感知对象处理

InstantiationAwareBeanPostProcessor.java

java 复制代码
package com.lino.springframework.beans.factory.config;

import com.lino.springframework.beans.BeansException;

/**
 * @description: 实例化感知对象处理
 */
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

    /**
     * 在 Bean 对象执行初始化方法之前,执行此方法
     *
     * @param beanClass 对象类
     * @param beanName  对象名
     * @return 新对象
     * @throws BeansException 异常
     */
    Object postProcessBeforeInitialization(Class<?> beanClass, String beanName) throws BeansException;
}

3.6.2 默认自动代理创建者

DefaultAdvisorAutoProxyCreator.java

java 复制代码
package com.lino.springframework.aop.framework.autoproxy;

import com.lino.springframework.aop.*;
import com.lino.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import com.lino.springframework.aop.framework.ProxyFactory;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.BeanFactory;
import com.lino.springframework.beans.factory.BeanFactoryAware;
import com.lino.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import com.lino.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import java.util.Collection;

/**
 * @description: 默认自动代理创建者
 */
public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {

    private DefaultListableBeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = (DefaultListableBeanFactory) beanFactory;
    }

    @Override
    public Object postProcessBeforeInitialization(Class<?> beanClass, String beanName) throws BeansException {
        if (isInfrastructureClass(beanClass)) {
            return null;
        }

        Collection<AspectJExpressionPointcutAdvisor> advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values();

        for (AspectJExpressionPointcutAdvisor advisor : advisors) {
            ClassFilter classFilter = advisor.getPointcut().getClassFilter();
            if (!classFilter.matches(beanClass)) {
                continue;
            }
            AdvisedSupport advisedSupport = new AdvisedSupport();

            TargetSource targetSource = null;
            try {
                targetSource = new TargetSource(beanClass.getDeclaredConstructor().newInstance());
            } catch (Exception e) {
                e.printStackTrace();
            }
            advisedSupport.setTargetSource(targetSource);
            advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
            advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
            advisedSupport.setProxyTargetClass(false);

            return new ProxyFactory(advisedSupport).getProxy();
        }

        return null;
    }

    private boolean isInfrastructureClass(Class<?> beanClass) {
        return Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass);
    }

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

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}
  • 这个 DefaultAdvisorAutoProxyCreator 类的主要核心实现在于 postProcessBeforeInitialization 方法中,通过 beanFactory.getBeanOfType 获取 AspectJExpressionPointcutAdvisor 开始。
  • 获取了 advisors 以后就可以遍历相应的 AspectJExpressionPointcutAdvisor 填充对应的属性信息,包括:目标对象、拦截方法、匹配器,在之后返回代理对象即可。
  • 现在调用方法获取到的这个 Bean 对象就是一个已经被切面注入的对象了,当调用方法的时候,则会被按需拦截,处理用户需要的信息。

3.7 融入到Bean的生命周期

AbstractAutowireCapableBeanFactory.java

java 复制代码
package com.lino.springframework.beans.factory.support;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValue;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.*;
import com.lino.springframework.beans.factory.config.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * @description: 实现默认bean创建的抽象bean工厂超类
 */
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {

    private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) {
        Object bean = null;
        try {
            // 判断是否返回代理 Bean 对象
            bean = resolveBeforeInstantiation(beanName, beanDefinition);
            if (null != bean) {
                return bean;
            }
            bean = createBeanInstance(beanDefinition, beanName, args);
            // 给bean填充属性
            applyPropertyValues(beanName, bean, beanDefinition);
            // 执行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置处理方法
            bean = initializeBean(beanName, bean, beanDefinition);
        } catch (Exception e) {
            throw new BeansException("Instantiation of bean failed", e);
        }

        // 注册实现 DisposableBean 接口的 Bean 对象
        registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);

        // 判断 SCOPE_SINGLETON、SCOPE_PROTOTYPE
        if (beanDefinition.isSingleton()) {
            registerSingletonBean(beanName, bean);
        }
        return bean;
    }

    private Object resolveBeforeInstantiation(String beanName, BeanDefinition beanDefinition) {
        Object bean = applyBeanPostProcessorsBeforeInstantiation(beanDefinition.getBeanClass(), beanName);
        if (null != bean) {
            bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
        }
        return bean;
    }

    private Object applyBeanPostProcessorsBeforeInstantiation(Class beanClass, String beanName) {
        for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
            if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
                Object result = ((InstantiationAwareBeanPostProcessor) beanPostProcessor).postProcessBeforeInitialization(beanClass, beanName);
                if (null != result) {
                    return result;
                }
            }
        }
        return null;
    }

    ...
}
  • 因为创建的是代理对象不是之前流程里的普通对象,所以我们需要前置于其他对象的创建,既需要在 AbstractAutowireCapableBeanFactory#createBean 优先完成 Bean 对象的判断,是否需要代理,有则直接返回代理对象。

四、测试:把AOP扩展到Bean的生命周期

4.1 添加测试配置

4.1.1 用户自定义拦截方法

UserServiceBeforeAdvice.java

java 复制代码
package com.lino.springframework.test.bean;

import com.lino.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;

/**
 * @description: 用户前拦截器
 */
public class UserServiceBeforeAdvice implements MethodBeforeAdvice {

    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("拦截方法:" + method.getName());
    }
}
  • 实现 MethodBeforeAdvice 环绕拦截。在这个方法中我们可以获取到方法的一些信息。

4.1.2 配置文件

spring.xml

xml 复制代码
<?xml version="1.0" encoding="utf-8" ?>
<beans>
    <bean id="userService" class="com.lino.springframework.test.bean.UserService"/>

    <bean class="com.lino.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

    <bean id="beforeAdvice" class="com.lino.springframework.test.bean.UserServiceBeforeAdvice"/>

    <bean id="methodInterceptor" class="com.lino.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor">
        <property name="advice" ref="beforeAdvice"/>
    </bean>

    <bean id="pointcutAdvisor" class="com.lino.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
        <property name="expression" value="execution(* com.lino.springframework.test.bean.IUserService.*(..))"/>
        <property name="advice" ref="methodInterceptor"/>
    </bean>
</beans>
  • 这次使用 AOP 可以像 Spring 中一样,通过在 xml 中配置即可。因为我们已经把 AOP 的功能融合到 Bean 的生命周期里去了,你的新增拦截方法都会被自动处理。

4.2 单元测试

4.2.0 测试环境初始化

ApiTest.java

java 复制代码
public class ApiTest {

    private AdvisedSupport advisedSupport;

    @Before
    public void init() {
        // 目标对象
        IUserService userService = new UserService();
        // 组装代理信息
        advisedSupport = new AdvisedSupport();
        advisedSupport.setTargetSource(new TargetSource(userService));
        advisedSupport.setMethodInterceptor(new UserServiceInterceptor());
        advisedSupport.setMethodMatcher(new AspectJExpressionPointcut("execution(* com.lino.springframework.test.bean.IUserService.*(..))"));

    }
}

4.2.1 前置拦截器测试

ApiTest.java

java 复制代码
@Test
public void test_beforeAdvice() {
    UserServiceBeforeAdvice beforeAdvice = new UserServiceBeforeAdvice();
    MethodBeforeAdviceInterceptor interceptor = new MethodBeforeAdviceInterceptor(beforeAdvice);
    advisedSupport.setMethodInterceptor(interceptor);

    IUserService proxy = (IUserService) new ProxyFactory(advisedSupport).getProxy();
    System.out.println("测试结果:" + proxy.queryUserInfo());
}

测试结果

java 复制代码
拦截方法:queryUserInfo
测试结果:张三,100001,杭州

4.2.2 拦截器访问者测试

ApiTest.java

java 复制代码
@Test
public void test_advisor() {
    // 目标对象
    IUserService userService = new UserService();

    AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
    advisor.setExpression("execution(* com.lino.springframework.test.bean.IUserService.*(..))");
    advisor.setAdvice(new MethodBeforeAdviceInterceptor(new UserServiceBeforeAdvice()));

    ClassFilter classFilter = advisor.getPointcut().getClassFilter();
    if (classFilter.matches(userService.getClass())) {
        AdvisedSupport advisedSupport = new AdvisedSupport();

        TargetSource targetSource = new TargetSource(userService);
        advisedSupport.setTargetSource(targetSource);
        advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
        advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
        advisedSupport.setProxyTargetClass(true);

        IUserService proxy = (IUserService) new ProxyFactory(advisedSupport).getProxy();
        System.out.println("测试结果:" + proxy.queryUserInfo());
    }
}

测试结果

java 复制代码
拦截方法:queryUserInfo
测试结果:张三,100001,杭州

4.2.3 单元测试

ApiTest.java

java 复制代码
@Test
public void test_aop() {
    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");

    IUserService userService = applicationContext.getBean("userService", IUserService.class);
    System.out.println("测试结果:" + userService.queryUserInfo());
}

测试结果

java 复制代码
拦截方法:queryUserInfo
测试结果:张三,100001,杭州
  • 从测试结果看,拦截方法已经生效了,也不需要手动处理切面、拦截方法等内容。

五、总结:把AOP扩展到Bean的生命周期

  • 本章实现 AOP 功能的外在体现主要是把以前在单元测试中的切面拦截,交给 Springxml 配置,也就不需要自己手动处理。
    • 如何把相应的功能与 SpringBean 生命周期结合起来,就是用到 BeanPostProcessor
    • 因为它可以解决在 Bean 对象执行初始化方法之前,用于修改新实例化 Bean 对象的扩展点,所以就可以处理 AOP 代理对象逻辑了。
相关推荐
2401_857439693 分钟前
SpringBoot框架在资产管理中的应用
java·spring boot·后端
怀旧6664 分钟前
spring boot 项目配置https服务
java·spring boot·后端·学习·个人开发·1024程序员节
李老头探索6 分钟前
Java面试之Java中实现多线程有几种方法
java·开发语言·面试
芒果披萨12 分钟前
Filter和Listener
java·filter
qq_49244844616 分钟前
Java实现App自动化(Appium Demo)
java
阿华的代码王国25 分钟前
【SpringMVC】——Cookie和Session机制
java·后端·spring·cookie·session·会话
找了一圈尾巴1 小时前
前后端交互通用排序策略
java·交互
哎呦没3 小时前
SpringBoot框架下的资产管理自动化
java·spring boot·后端
m0_571957585 小时前
Java | Leetcode Java题解之第543题二叉树的直径
java·leetcode·题解
魔道不误砍柴功7 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python