Spring AOP之---基于ProxyFactory的类编码方式和XML配置方式实现AOP

前一篇文章Spring AOP之—基于JDK动态代理和CGLib动态代理的AOP实现 介绍了AOP的底层实现,基于JDK动态代理和CGLib动态代理。手工编码的方式很繁琐,本文介绍通过ProxyFactory和配置的方式实现AOP,方便快捷。

一、Spring支持的5种增强类型

增强是织入目标类连接点上的一段程序代码。

  • 前置增强:MethodBeforeAdvice方法执行前实施增强
  • 后置增强:AfterReturningAdvice方法执行后实施增强
  • 环绕增强: MethodInterceptor方法执行前后实施增强
  • 异常抛出增强: ThrowsAdvice方法抛出异常后实施增强,最适合的应用场景就是事物管理。
  • 引介增强:IntroductionInterceptor在目标类中添加一些新的方法和属性

二、类编码的方式实现增强织入

1、目标类需要实现的接口 — Waiter

package com.mistra.aop.createAdvice;

/** * @author Mistra-WangRui * @create 2018/3/28 15:50 * @desc 目标类要实现的接口 */
public interface Waiter {
    void greetTo(String name);
    void serveTo(String name);
}

2、目标类 — NaiveWaiter

package com.mistra.aop.createAdvice;

/** * @author Mistra-WangRui * @create 2018/3/28 15:51 * @desc 目标类 */
public class NaiveWaiter implements Waiter{
    public void greetTo(String name) {
        System.out.println("greet to + "+name+"...");
    }

    public void serveTo(String name) {
        System.out.println("serving to + "+name+"...");
    }
}

3、前置增强类 — GreetingBeforeAdvice

package com.mistra.aop.createAdvice;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

/** * @author Mistra-WangRui * @create 2018/3/28 15:55 * @desc 前置增强类 */
public class GreetingBeforeAdvice implements MethodBeforeAdvice {
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        String clientName = (String)objects[0];
        System.out.println("How are you! Mr."+clientName+".");
    }
}

MethodBeforeAdvice 接口唯一的方法before(),method为目标类的方法,objects为method的入参,o为目标类实例。

4、类编码方式实现增强织入

package com.mistra.aop.createAdvice;

import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
import org.testng.annotations.Test;

/** * @author Mistra-WangRui * @create 2018/3/28 15:58 * @desc 编码方式实现横切逻辑增强 */
public class BeforeAdviceTest {
    @Test
    public void before(){
        Waiter waiter = new NaiveWaiter();
        BeforeAdvice advice = new GreetingBeforeAdvice();
        ProxyFactory pf = new ProxyFactory();//Spring提供的代理工厂
        //pf.setInterfaces(waiter.getClass().getInterfaces());
        //pf.setOptimize(true);
        pf.setTarget(waiter);//设置代理目标
        pf.addAdvice(advice);//为代理目标添加增强
        Waiter proxy = (Waiter)pf.getProxy();//生成代理实例
        proxy.greetTo("古天乐");
        proxy.serveTo("吴彦祖");
    }
}

运行结果:
Spring AOP之---基于ProxyFactory的类编码方式和XML配置方式实现AOP_第1张图片

5、ProxyFactory 解析

在BeforeAdviceTest中使用ProxyFactory代理工厂将GreetingBeforeAdvice的增强织入目标类NaiveWaiter中。ProxyFactory 内部就是使用JDK或CGLib动态代理技术将增强应用到目标类中的。
setInterfaces()指定目标接口进行代理,则ProxyFactory使用JDK动态代理(实现类:JdkDynamicAopProxy)技术创建代理。如果针对类的代理,则使用CGLib动态代理(实现类:Cglib2AopProxy)。
setOptimize(true)是启动优化处理方式,这样针对接口的代理也会使用CGLib动态代理。
可以为该方法添加多个增强,形成一个增强链,它们的调用顺序和添加顺序一致。可以通过addAdvice(int,Advice)方法将增强添加到增强链具体位置(第一个位置为0)。

三、Spring配置的方式实现增强织入

包结构目录放在前面:
Spring AOP之---基于ProxyFactory的类编码方式和XML配置方式实现AOP_第2张图片

1、配置文件 — beans.xml


<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="greetingAdvice" class="com.mistra.aop.createAdvice.GreetingBeforeAdvice"/>
    <bean id="target" class="com.mistra.aop.createAdvice.NaiveWaiter"/>
    <bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean" p:proxyInterfaces="com.mistra.aop.createAdvice.Waiter" p:interceptorNames="greetingAdvice" p:target-ref="target" />
beans>

ProxyFactoryBean是FactoryBean接口的实现类,FactoryBean负责实例化一个Bean,ProxyFactoryBean负责为其他Bean创建代理实例,内部使用ProxyFactory来完成这项工作,ProxyFactoryBean的几个常用配置属性:

  • target:代理的目标对象
  • proxyInterfaces:代理所需实现的接口,可以是多个
  • interceptorNames:需要织入目标对象的Bean列表,配置中的顺序对应调用的顺序
  • singleton:返回的代理实例是否是单实例,默认为单实例
  • optimize:设置为true时,强制使用CGLib动态代理(对于singleton的代理用CGLib,其他作用域的用JDK),CGLib代理时速度慢,但是创建的代理对象运行效率高,JDK反之
  • proxyTargetClass:是否对类进行代理,设置为true时使用CGLib代理

2、配置方式实现横切逻辑增强 — BeforeAdviceTest2

package com.mistra.aop.createAdvice;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.Test;

/** * @author Mistra-WangRui * @create 2018/3/29 11:11 * @desc 配置方式实现横切逻辑增强 */
public class BeforeAdviceTest2 {
    @Test
    public void test(){
        String configPath = "com.mistra/aop/createAdvice/beans.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
        Waiter waiter = (Waiter)ctx.getBean("waiter");
        waiter.greetTo("古天乐");
    }
}

本文只介绍了前置增强,其他的增强都大同小异。
本文这样实施增强的话是把增强织入了目标类的所有方法中,调用目标类的所有方法时都会执行增强逻辑代码。有时候希望有选择的把增强织入目标类的特定方法中,就需要使用切点进行目标类连接点的定位。

四、Spring AOP其他

1、定义切面Advisor:有选择性的织入增强到某些类的某些方法

2、自动创建代理:上文都是通过ProxyFactoryBean创建的目标类代理,Spring AOP通过BeanPostProcessor可以自动为目标类创建代理

3、无法实现增强的问题:在JDK动态代理中通过接口来实现方法拦截,必须确保要拦截的目标方法在接口中有定义。在CGLib动态代理中通过动态代理子类来实现方法拦截,必须确保要拦截的目标方法可被子类访问,也就是目标方法不能被定义为final。

五、基于@AspectJ和Schema的AOP

@AspectJ和Schema都是实现AOP的方式,@AspectJ支持编码的方式和配置的方式实现AOP,Schema就是运用
< aop:config>< /aop:config>标签配置实现AOP。难点就是@AspectJ的语法基础和其中的配置切点表达式函数吧。无论用哪种方式实现AOP,底层原理都是运用JDK或者是CGLib动态代理技术。在运行期动态生成目标类的代理类实现的。

你可能感兴趣的:(Spring)