Spring AOP之简单实践

Spring AOP建立在代理之上,所以先对代理有个简单的认识也是很有必要的,下面结合代码来进行简要说明。

1,首先定义一个接口和实体对象

public class Student {
    public String name ;
    public int age ;
}
public interface IStudentService {
    /**
     * 添加学生
     * */
    void addStudent(Student student) ;
    /**
     * 删除学生
     * */
    void removeStudent(String studentId) ; 
}
public class DefaultStudentService implements IStudentService {
    @Override
    public void addStudent(Student student) {
        System.out.println("新增学生信息");
    }
    @Override
    public void removeStudent(String studentId) {
        System.out.println("删除ID为" + studentId+"的学生信息");
    }
}

2,Java的动态代理技术

Java的动态代理主要涉及到下面两个类型
1)java.lang.reflect.InvocationHandler接口

/**
代理实例的调用处理程序实现的接口;
每个代理实例都有一个关联的调用处理程序。
在代理实例上调用方法时,方法调用将被处理并发送到其调用处理程序的invoke方法。
*/
public interface InvocationHandler {
    /**
            @param proxy 动态生成的代理对象实例
            @param method 被代理对象调用的方法
            @param args 被调用的方法的参数
            @return 从代理实例上的方法调用返回的值,其类型必须和被代理接口中所定义的返回类型兼容。
    */
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

2)java.lang.reflect.Proxy对象

简单的说,Java动态代理就是通过Java的Proxy对象来创建某个实例对象的代理对象,在调用代理对象的时候便会触发调用InvocationHandler的invoke方法,我们在invoke方法中可以添加一些额外的代码来扩充能力,同时在invoke中我们可以判断哪个方法被调用,然后通过反射执行被代理对象上的这个方法。

3,使用Java动态代理实例

/**
     * Java的动态代理技术【代理整个接口类】
     */
    public static void javaDyncProxy() {
        // 要被代理的目标对象
        DefaultStudentService studentService = new DefaultStudentService();
        // 代理的调用处理器【当我们通过动态代理对象调用任何一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用】
        StudentServiceInvocationHandler invocationHandler = new StudentServiceInvocationHandler(studentService);
        // 创建代理对象
        IStudentService service = (IStudentService)Proxy.newProxyInstance(studentService.getClass().getClassLoader(),
                studentService.getClass().getInterfaces(), invocationHandler);
        service.addStudent(new Student());
    }
    public static class StudentServiceInvocationHandler implements InvocationHandler {
        private IStudentService target;
        public StudentServiceInvocationHandler(IStudentService studentService) {
            this.target = studentService;
        }

        /*
         * @param proxy
         * 真实对象的真实代理对象;InvocationHandler本身,例如这里的:StudentServiceInvocationHandler
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("是的,你已经是在使用Proxy了");
            return method.invoke(target, args);
        }
    }
    public static void main(String[] args) {
         javaDyncProxy() ;
    }

执行main方法后,得到的打印输入如下

是的,你已经是在使用Proxy了
新增学生信息

4,Spring AOP

前面的文章中有介绍过Spring AOP中的一些概念,其中包括Advice和Pointcut。 Pointcut用于筛选类和方法,而Advice负责确实执行点,通过两则的结合就有了Advisor(切面)。

我们先看下SpringAOP中这些对象的关系。

Spring AOP之简单实践

由上图可知
1)Pointcut接口依赖于ClassFilter和MethodMatcher两个接口,通过这两个接口来达到筛选类和方法的目的
2)Advice接口【是个Tag Interface】包含了众多的子接口,通过子接口来扩展其功能,每个子接口都分别代表不同的方法执行点(内部的抽象方法便是添加增强代码的地方)
3)Adisor接口依赖于Advice接口,代表一个类中的所有方法的某些执行点,其最常用的子接口类型PointcutAdvisor有添加了对Pointcut接口的依赖,表示某些类中某些方法的某些执行点

下面我们更进一步的看看各个接口都有哪些实现

Pointcut实现类关系图

Spring AOP之简单实践

Advice接口关系图

Spring AOP之简单实践

ThrowsAdvice是一个Tag interface,实现类具有以下任意一个或多个方法实现均可:
public void afterThrowing(Exception ex)
public void afterThrowing(RemoteException)
public void afterThrowing(Method method, Object[] args, Object target, Exception ex)
public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)

Advisor关系图

Spring AOP之简单实践

上面通过类图展现了SpringAOP中几个关键概念间的关系,下面再看看SpringProxy的类图

Spring AOP之简单实践

1)ProxyCreatorSupport与AopProxyFactory关联,在内部默认创建DefaultAopProxyFactory对象

2)AopProxyFactory依赖AopProxy接口,AopProxy的实现类包含了基于Java动态代理的JdkDynamicAopProxy和基于cglib的CglibAopProxy对象

3)我们在使用AopProxy的时候,内部会根据我们的设置来动态的选择使用Java动态代理还是基于cglib的代理。

下面通过示例代码来说明Spring Aop的以上这些对象

创建增强

/**
 * 定义“方位”以及对应的增强代码。
 * 使用时,如果没提供具体的Ponitcut,该增强会织入到目标类的所有方法上。
 * */
public class StudentServiceAdvice implements MethodBeforeAdvice, AfterReturningAdvice,ThrowsAdvice {

    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("调用方法" + method.getName() +"前");
    }

    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("调用方法" + method.getName() +"返回后");
    }

    /**
     * 方法名必须是afterThrowing,前三个参数是可选【同时都出现或都不出现】,最后个参数不行是Throwable或子类。
     * 可以定义多个afterThrowing方法,Spring会自动选用最匹配的增强方法。
     * */
    public void afterThrowing(Method method, Object[] args, Object target,RuntimeException e) {
        System.out.println("调用方法" + method.getName() +"抛出异常后");
    }
}

创建代理

/**
     * 只用增强应用到类上的所有方法上
     */
    public static void springProxy() {
        // 要被代理的目标对象
        DefaultStudentService studentService = new DefaultStudentService();
        /*
         * 代理工厂根据代理配置在内部使用AopProxy类型的代理创建代理对象,AopProxy的实现类有以下两个: 
         * 1)JdkDynamicAopProxy :基于Java的动态代理技术 
         * 2)Cglib2AopProxy : 基于CGLib的动态代理技术
         * 在使用ProxyFactory的时候,如果通过setInterface()方法指定目标接口进行代理,则使用JdkDynamicAopProxy;
         * 如果针对类的代理或者设置SetOptimize(true),则使用Cglib2AopProxy;
         */
        ProxyFactory factory = new ProxyFactory();
        // 设置要被代理的接口类型
        factory.setInterfaces(studentService.getClass().getInterfaces());
        // 设置代理的目标对象
        factory.setTarget(studentService);
        // 为代理目标添加增强[Advice包含了横切代码和连接点信息,所以本身就是一个简单的切面,其他的所有切面类型也都继承于Advice]
        factory.addAdvice(new StudentServiceAdvice());
        // 生成代理实例
        IStudentService proxy = (IStudentService) factory.getProxy();
        // 调用方法
        proxy.addStudent(new Student("test", 22));
        proxy.removeStudent("10001");
    }

执行后的输出结果:

调用方法addStudent前
新增学生信息
调用方法addStudent返回后
调用方法removeStudent前
删除ID为10001的学生信息
调用方法removeStudent返回后

猜你喜欢

转载自blog.51cto.com/dengshuangfu/2400191