chapter12_将AOP融入Spring

将AOP融入到Spring,依然是使用Bean后置处理器,最关键的类DefaultAdvisorAutoProxyCreator

一、通知

通知是对方法拦截器逻辑的细化,本次我们只实现前置通知

  • 前置通知
  • 后置通知
  • 环绕通知
  • 异常通知

新建前置通知接口BeforeAdvice,继承aop_alliance的Advice接口,做统一包装

public interface BeforeAdvice extends Advice {

}

新建方法前置通知接口MethodBeforeAdvice,继承BeforeAdvice

  • 定义一个before方法
  • 由实现类提供before的具体逻辑
public interface MethodBeforeAdvice extends BeforeAdvice {
    void before(Method method, Object[] args, Object target) throws Throwable;
}

新建顾问Advisor接口,顾名思义,顾问就是用来提供建议的

  • 提供一个获取建议的方法,
public interface Advisor {
    Advice getAdvice();
}

新建切点顾问子接口,继承顾问

  • 顾问需要关联具体的切点
  • 提供一个获取切点的方法
public interface PointcutAdvisor extends Advisor{

    /**
     * Get the Pointcut that drives this advisor.
     */
    Pointcut getPointcut();
}

新建一个实现类AspectJExpressionPointcutAdvisor,融合上述所有的概念

在这里插入图片描述

  • 切点
  • 通知
  • 表达式
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;
    }
}

新建方法前置通知拦截器,实现aop_alliance提供的MethodInterceptor接口

  • 目的是为了将方法拦截器进行分类
  • 专注于处理前置增强逻辑
public class MethodBeforeAdviceInterceptor implements MethodInterceptor {
    private MethodBeforeAdvice advice;

    public MethodBeforeAdviceInterceptor() {
    }

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

    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
        return mi.proceed();
    }
}

二、融入Spring

修改包装类AdvisedSupport

  • 新增proxyTargetClass属性,判断是否使用cglib,默认false
@Data
public class AdvisedSupport {
    // 是否开启cglib,默认false
    private boolean proxyTargetClass = false;

    // 目标对象
    private TargetSource targetSource;

    // 通知
    private MethodInterceptor methodInterceptor;

    // 方法匹配器
    private MethodMatcher methodMatcher;
}

新建代理工厂

  • 工厂模式
  • 用于获取AopProxy
public class ProxyFactory {
    private final 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);
    }
}

新建Bean后置处理器子接口InstantiationAwareBeanPostProcessor,继承于BeanPostProcessor

  • 扩展一个新方法,在Bean实例化前执行
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor{
    /**
     * 在 Bean 对象执行实例化方法之前,执行此方法
     * @param beanClass
     * @param beanName
     * @return
     */
    Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName);
}

新建融入Spring的关键类DefaultAdvisorAutoProxyCreator

  • 实现InstantiationAwareBeanPostProcessor
  • 实现BeanFactoryAware
public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {
    private DefaultListableBeanFactory beanFactory;

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

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
        // 基础设施的Bean不用被代理
        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;
    }

    /**
     * 判断一个Bean是否是基础设施类
     * @param beanClass
     * @return
     */
    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) {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }
}

重写createBean方法

  • 暂时简化处理,直接判断是否返回代理对象
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) {
    Object bean = null;
    // 判断是否需要返回代理Bean对象
    bean = resolveBeforeInstantiation(beanName, beanDefinition);
    if (null != bean) {
        return bean;
    }
    // 实例化,包括构造函数注入
    bean = doCreateBean(beanName, beanDefinition, args);
    // 依赖注入
    populateBean(beanName, bean, beanDefinition);
    // 初始化
    bean = initializeBean(beanName, bean, beanDefinition);
    // 注册实现了 DisposableBean 接口的 Bean 对象
    registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);
    // 是否加入单例池
    if (beanDefinition.isSingleton()) {
        addSingleton(beanName, bean);
    }
    return bean;
}

protected Object resolveBeforeInstantiation(String beanName, BeanDefinition beanDefinition) {
    Object bean = applyBeanPostProcessorsBeforeInstantiation(beanDefinition.getBeanClass(), beanName);
    if (null != bean) {
        bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
    }
    return bean;
}
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
        if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
            Object result = ((InstantiationAwareBeanPostProcessor) beanPostProcessor).postProcessBeforeInstantiation(beanClass, beanName);
            if (null != result) return result;
        }
    }
    return null;
}

三、测试

自定义方法拦截器

public class CatBeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("猫前置增强:" + method.getName());
    }
}

创建前置通知

  • 手动组装到Spring的前置方法拦截器
public class CatBeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("猫前置增强:" + method.getName());
    }
}

编写spring.xml,主要就是cat,DefaultAdvisorAutoProxyCreator,pointcutAdvisor(顾问,以及需要的方法拦截器)

  • cat,被拦截的类
  • Aop核心类,DefaultAdvisorAutoProxyCreator放进容器
  • 通知,CatBeforeAdvice
  • 方法拦截器,catInterceptor
  • 顾问,pointcutAdvisor
<?xml version="1.0" encoding="UTF-8"?>
<beans>

    <bean id="cat" class="cn.shopifymall.springframework.test.bean.Cat"/>

    <bean class="cn.shopifymall.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

    <bean id="catBeforeAdvice" class="cn.shopifymall.springframework.test.bean.CatBeforeAdvice"/>

    <bean id="catInterceptor" class="cn.shopifymall.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor">
        <property name="advice" ref="catBeforeAdvice"/>
    </bean>

    <bean id="pointcutAdvisor" class="cn.shopifymall.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
        <property name="expression" value="execution(* cn.shopifymall.springframework.test.bean.Eat.*(..))"/>
        <property name="advice" ref="catInterceptor"/>
    </bean>
</beans>

在refresh()方法里面,首先会加载DefaultAdvisorAutoProxyCreator(BeanPostProcessor),然后实例化Cat

测试类

@Test
    public void test_auto_aop() {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:springTest.xml");
        Eat cat = (Eat) applicationContext.getBean("cat");
        System.out.println("测试结果:" + cat.eatFish("大马哈鱼"));
    }

结果

猫前置增强:eatFish
20:18:30.957 [main] INFO cn.shopifymall.springframework.test.bean.Cat - 猫正在吃鱼
测试结果:吃了一条大马哈鱼

断点查看,Cat是代理对象

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值