博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring AOP之简单实践
阅读量:6712 次
发布时间:2019-06-25

本文共 6797 字,大约阅读时间需要 22 分钟。

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的以上这些对象

使用ProxyFactory

/** * 定义“方位”以及对应的增强代码。 * 使用时,如果没提供具体的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包含了横切代码和连接点信息,所以本身就是一个简单的切面]        factory.addAdvice(new StudentServiceAdvice());        // 生成代理实例        IStudentService proxy = (IStudentService) factory.getProxy();        // 调用方法        proxy.addStudent(new Student("test", 22));        proxy.removeStudent("10001");    }

执行后的输出结果:

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

使用AspectJProxyFactory

org.aspectj
aspectjweaver
1.9.4
org.aspectj
aspectjrt
1.9.4
@Aspectpublic class CommAspect {    /**     * 前置增强     * 所有目标类中的所有addStudent方法     * */    @Before("execution (* addStudent(..))")    public void defore(JoinPoint joinPoint) {        System.out.println(">>>>befor addStudent");    }}public static void springAspectProxy() {        // 要被代理的目标对象        DefaultStudentService studentService = new DefaultStudentService();        // 基于AspectJ的代理工厂        AspectJProxyFactory factory = new AspectJProxyFactory();        // 设置代理目标        factory.setTarget(studentService);        // 添加切面类        factory.addAspect(CommAspect.class);        // 生成代理实例        IStudentService proxy = (IStudentService) factory.getProxy();        // 调用方法        proxy.addStudent(new Student("test", 22));        proxy.removeStudent("10001");    }

执行后输出:

>>>>befor addStudent新增学生信息删除ID为10001的学生信息

转载于:https://blog.51cto.com/dengshuangfu/2400191

你可能感兴趣的文章
IBM推出实时跨境支付解决方案Blockchain World Wire
查看>>
IBM中国开发中心吉燕勇: 通过Cloud Data Services打造新型认知计算数据分析云平台...
查看>>
Hybrid App走向“轻混”,剖析WeX5开源高性能HTML5 App开发框架
查看>>
网易戏精ARCore短视频新玩法实践
查看>>
华泰证券:如何自研高效可靠的交易系统通信框架?
查看>>
使用Flutter之后,我们的CPU占用率降了50%
查看>>
我们究竟应不应该使用框架?
查看>>
如何基于Kubernetes构建完整的DevOps流水线
查看>>
Deis发布1.4版本,支持Microsoft Azure
查看>>
用于.NET Core的ORM
查看>>
慎用!BLEU评价NLP文本输出质量存在严重问题
查看>>
如何撰写好文档?精益文档的六个实践
查看>>
ArchSummit微课堂|蘑菇街DevOps实践及心路历程分享
查看>>
随手记统一监控平台Focus设计解析
查看>>
中国平安“豪赌”科技?从产险业务IT变形计聊起
查看>>
RSocket:一个面向反应式应用程序的新型应用网络协议
查看>>
ElasticSearchDsl
查看>>
SciPy达到1.0版本,有了新的治理结构
查看>>
IntelliJ IDEA 2018.3 新版本发布,支持 Java 12及Spring Boot增强等特性
查看>>
Go语言很好很强大,但我有几个问题想吐槽
查看>>