博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring AOP
阅读量:5263 次
发布时间:2019-06-14

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

什么叫AOP?

  这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。

面向切面编程(AOP是Aspect Oriented Program的首字母缩写) ,我们知道,面向对象的特点是继承、多态和封装。而封装就要求将功能分散到不同的对象中去,这在软件设计中往往称为职责分配。 实际上也就是说,让不同的类设计不同的方法。这样代码就分散到一个个的类中去了。这样做的好处是降低了代码的复杂程度,使类可重用。      但是人们也发现,在分散代码的同时,也增加了代码的 重复性。什么意思呢?比如说,我们在两个类中,可能都需要在每个方法中做日志。按面向对象的设计方法,我们就必须在两个类的方法中都加入日志的内容。也许他们是完全相同的,但就是因为面向对象 的设计让类与类之间无法联系,而不能将这些重复的代码统一起来。    也许有人会说,那好办啊,我们可以将这段代码写在一个独立的类独立的方法里,然后再在这两个类中调用。但是,这样一来,这两 个类跟我们上面提到的独立的类就有耦合了,它的改变会影响这两个类。那么,有没有什么办法,能让我们在需要的时候,随意地加入代码呢?这种在运行时,动态地将代码切入到类的指定方法、指定位置 上的编程思想就是面向切面的编程。       一般而言,我们管切入到指定类指定方法的代码片段称为切面,而切入到哪些类、哪些方法则叫切入点。有了AOP,我们就可以把几个类共有的代码,抽取到一 个切片中,等到需要时再切入对象中去,从而改变其原有的行为。这样看来,AOP其实只是OOP的补充而已。OOP从横向上区分出一个个的类来,而AOP则从纵向上向对象中加入特定的代码。有了AOP,OOP 变得立体了。如果加上时间维度,AOP使OOP由原来的二维变为三维了,由平面变成立体了。从技术上来说,AOP基本上是通过代理机制实现的。

1.代理模式readMe:

1 代理设计模式: 是java中常用的设计模式! 2  3    特点: 4        01.委托类和代理类有相同的接口或者共同的父类! 5        02.代理类为委托类负责处理消息,并将消息转发给委托类! 6        03.委托类和代理类对象通常存在关联关系! 7           一个代理类对象与一个委托类对象关联! 8        04.代理类本身并不是真正的实现者!而是通过调用委托类的方法, 9           来实现功能!10 11 12    按照代理类创建的时机,代理类分为两种:13    01.静态代理:由我们程序猿或者特定的工具自动生成了源代码,14                  在程序运行之前,.class文件已经存在了!15       (serviceImpl 调用了 dao层的方法! 真正的实现是Dao)16    02.动态代理:在程序运行期间,通过反射的方式动态的创建出来!17 18 19    按照我们的使用方式:  是由共同的接口还是公共的父类?20 21      01.jdk动态代理 (接口)22           必须知道一个类和一个接口23            001.InvocationHandler接口只有一个方法24 25             public Object invoke(Object proxy, Method method, Object[] args)26                    throws Throwable;27 28            proxy:代理类对象29            method:被代理的方法30            args:被代理的方法的参数列表31 32           002.Proxy 类:33            public static Object newProxyInstance(ClassLoader loader,34                   Class
[] interfaces,InvocationHandler h)throws IllegalArgumentException35 loader:类加载器36 interfaces:代理类实现的所有接口37 h:InvocationHandler接口的一个实例 this当前对象38 因为我们想使用jdk动态代理 必须是 代理类 实现 InvocationHandler!39 它让我们传递父接口 我们传递 自身!40 41 02.cglib动态代理(接口+父类)42 必须知道一个类和一个接口43 001.MethodInterceptor接口44 45 public Object intercept(Object obj,46 Method method,Object[] args,MethodProxy proxy) throws Throwable;47 48 intercept是所有拦截器执行的方法,类似于jdk动态代理中的invoke49 50 51 002. Enhancer类52 53 设置委托类和代理类的公共接口或者公共的父类54 public void setSuperclass(Class superclass) {55 if (superclass != null && superclass.isInterface()) {56 setInterfaces(new Class[]{ superclass });57 } else if (superclass != null && superclass.equals(Object.class)) {58 // affects choice of ClassLoader59 this.superclass = null;60 } else {61 this.superclass = superclass;62 }63 }64 65 代理类执行完毕 通知委托类66 public void setCallback(final Callback callback) {67 setCallbacks(new Callback[]{ callback });68 }69 70 71 在Enhancer类的父类AbstractClassGenerator中有一个方法72 创建我们需要的代理类73 protected Object create(Object key)

2.静态代理:

01.接口代码:

package cn.pb.dao;/** * 动物类 父接口 */public interface Animal {    //主业务    void eat();    void sleep();}

02.实现类代码:

package cn.pb.dao.impl;/** * 狗狗类 实现了Animal接口 */import cn.pb.dao.Animal;public class Dog implements Animal {    public void eat() {        System.out.println("狗狗在啃骨头!");    }    public void sleep() {        System.out.println("狗狗在午休!");    }}

03.静态代理类:

package cn.pb.staticproxy;import cn.pb.dao.Animal;import cn.pb.dao.impl.Dog;/** * 狗狗的静态代理类 */public class AnimalStaticProxy implements Animal {    private Dog dog;    public void sleep() {        System.out.println("主人在召唤");  //系统级业务        dog.sleep();        System.out.println("主人离开"); //系统级业务    }    public void eat() {        System.out.println("主人在召唤"); //系统级业务        dog.eat();        System.out.println("主人离开"); //系统级业务    }    public Dog getDog() {        return dog;    }    public void setDog(Dog dog) {        this.dog = dog;    }    /**     * 我们发现的问题     * 01:代码冗余     * 02:把冗余的代码提取成公共的方法     * 03:有可能小猫咪也有这些方法     * 04:提取成一个工具类中的方法     * 05:现在有一个小猫咪 也需要执行 sleep和eat 以及系统级业务方法     * 06:我们又得创建一个小猫咪对应的代理类     * 07:动物有很多  ,难道需要我们创建N个代理类吗??肯定!     */}

04.测试类代码:

/**     * 静态代理的测试方法     */    @Test    public void testStaticProxy(){        AnimalStaticProxy proxy = new AnimalStaticProxy();        Dog dog=new Dog();        proxy.setDog(dog);        proxy.eat();        System.out.println("*************");        proxy.sleep();    }

3.JDK动态代理:

01.接口代码:

package cn.pb.dao;/** * 动物类 父接口 */public interface Animal {    //主业务    void eat();    void sleep();}

02.实现类代码:

package cn.pb.dao.impl;/** * 狗狗类 实现了Animal接口 */import cn.pb.dao.Animal;public class Dog implements Animal {    public void eat() {        System.out.println("狗狗在啃骨头!");    }    public void sleep() {        System.out.println("狗狗在午休!");    }}

03.动态代理类代码:

package cn.pb.jdkdynamicproxy;/** * JDK的动态代理类 */import cn.pb.dao.Animal;import cn.pb.dao.impl.Dog;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class AnimalJdkDynamicProxy implements InvocationHandler {    /**     *  01.我们不确定委托类是谁?委托类的类型 是Object     *   和委托类建立关联关系     */    private Object target;    /**     * 02.给我一个委托类,我返回一个代理类对象     */    public Object createProxy(Object target){        //根据传递的参数 进行对象的关联        this.target=target;        return Proxy.newProxyInstance(target.getClass().getClassLoader(),                target.getClass().getInterfaces(), this);    }    /**     *     * @param proxy :代理对象     * @param method :方法名     * @param args : 参数列表     * @return     */    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println("主人在召唤"); //系统级业务   开始事务        Object result= method.invoke(target,args);  // 主业务        System.out.println("主人离开"); //系统级业务     日志处理  关闭事务        return result;    }    //创建测试方法    public static void main(String[] args) {        AnimalJdkDynamicProxy proxy=new AnimalJdkDynamicProxy();        Animal dog= (Animal) proxy.createProxy(new Dog());        dog.eat();        System.out.println("**************************");        dog.sleep();    }}

04.测试代码:

@Test    public void testJdkDynamicProxy(){        AnimalJdkDynamicProxy proxy=new AnimalJdkDynamicProxy();        Animal dog= (Animal) proxy.createProxy(new Dog());        dog.eat();        System.out.println("**************************");        dog.sleep();    }

4.cglib动态代理:

01.接口代码:

package cn.pb.dao;/** * 动物类 父接口 */public interface Animal {    //主业务    void eat();    void sleep();}

02.实现类代码:

package cn.pb.dao.impl;/** * 狗狗类 实现了Animal接口 */import cn.pb.dao.Animal;public class Dog implements Animal {    public void eat() {        System.out.println("狗狗在啃骨头!");    }    public void sleep() {        System.out.println("狗狗在午休!");    }}

03.动态代理类代码:

package cn.pb.cglibdynamicproxy;/** * Cglib动态代理 */import cn.pb.dao.Animal;import cn.pb.dao.impl.Dog;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class AnimalCglibDynamicProxy implements MethodInterceptor {    /**     * 在enhancer中有一个setCallBack(this)     * 这样就实现了代理类和委托类的关联     */    private Enhancer enhancer=new Enhancer();    /**     *  创建代理类对象     */    public  Object  createProxy(Class clazz){        //设置公共的接口或者公共的类        enhancer.setSuperclass(clazz);        //建立关联关系        enhancer.setCallback(this);        return enhancer.create();    }    /**     * 类似于我们jdk中的invoke     */    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {        System.out.println("主人在召唤"); //系统级业务   开始事务        Object result= proxy.invokeSuper(obj,args);  // 主业务        System.out.println("主人离开"); //系统级业务     日志处理  关闭事务        return result;    }    //创建测试方法    public static void main(String[] args) {        AnimalCglibDynamicProxy proxy=new AnimalCglibDynamicProxy();        //这里的参数可以传三种形式01:new Dog().getClass()        // 02:Class.forName("cn.pb.dao.impl.Dog") 03.Dog.class        Animal dog= (Animal) proxy.createProxy(new Dog().getClass());        dog.eat();        System.out.println("**************************");        dog.sleep();    }}

04.测试代码:

@Test    public void testCglibDynamicProxy(){        AnimalJdkDynamicProxy proxy=new AnimalJdkDynamicProxy();        Animal dog= (Animal) proxy.createProxy(new Dog());        dog.eat();        System.out.println("**************************");        dog.sleep();    }

 

 

 

就是在方法前或后要做的一些事情。AOP中官方叫法为“切面” 如果写到方法中。后期维护很难。

1:核心代码

1 package com.spring.aop; 2  3 public interface ArithmeticCalculator { 4  5     int add(int i, int j); 6     int sub(int i, int j); 7      8     int mul(int i, int j); 9     int div(int i, int j);10     11 }
1 package com.spring.aop; 2  3 import org.springframework.stereotype.Component; 4  5 @Component("arithmeticCalculator") 6 public class ArithmeticCalculatorImpl implements ArithmeticCalculator { 7  8     public int add(int i, int j) { 9         int result = i + j;10         return result;11     }12 13     public int sub(int i, int j) {14         int result = i - j;15         return result;16     }17 18     public int mul(int i, int j) {19         int result = i * j;20         return result;21     }22 23     public int div(int i, int j) {24         int result = i / j;25         return result;26     }27 28 }

2:写一个切面的类

package com.spring.aop; import java.util.Arrays; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /**  * 可以使用 @Order 注解指定切面的优先级, 值越小优先级越高  */ @Order(1) @Aspect @Component public class LoggingAspect {
         /**      * 定义一个方法, 用于声明切入点表达式. 一般地, 该方法中再不需要添入其他的代码.      * 使用 @Pointcut 来声明切入点表达式.      * 后面的其他通知直接使用方法名来引用当前的切入点表达式.      */     @Pointcut("execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(..))")     public void declareJointPointExpression(){}          /**      * 在 com.atguigu.spring.aop.ArithmeticCalculator 接口的每一个实现类的每一个方法开始之前执行一段代码      */     @Before("declareJointPointExpression()")     public void beforeMethod(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();         Object [] args = joinPoint.getArgs();                  System.out.println("The method " + methodName + " begins with " + Arrays.asList(args));     }          /**      * 在方法执行之后执行的代码. 无论该方法是否出现异常      */     @After("declareJointPointExpression()")     public void afterMethod(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();         System.out.println("The method " + methodName + " ends");     }          /**      * 在方法法正常结束受执行的代码      * 返回通知是可以访问到方法的返回值的!      */     @AfterReturning(value="declareJointPointExpression()",             returning="result")     public void afterReturning(JoinPoint joinPoint, Object result){
        String methodName = joinPoint.getSignature().getName();         System.out.println("The method " + methodName + " ends with " + result);     }          /**      * 在目标方法出现异常时会执行的代码.      * 可以访问到异常对象; 且可以指定在出现特定异常时在执行通知代码      */     @AfterThrowing(value="declareJointPointExpression()",             throwing="e")     public void afterThrowing(JoinPoint joinPoint, Exception e){
        String methodName = joinPoint.getSignature().getName();         System.out.println("The method " + methodName + " occurs excetion:" + e);     }          /**      * 环绕通知需要携带 ProceedingJoinPoint 类型的参数.      * 环绕通知类似于动态代理的全过程: ProceedingJoinPoint 类型的参数可以决定是否执行目标方法.      * 且环绕通知必须有返回值, 返回值即为目标方法的返回值      */     /*     @Around("execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(..))")     public Object aroundMethod(ProceedingJoinPoint pjd){
                 Object result = null;         String methodName = pjd.getSignature().getName();                  try {
            //前置通知             System.out.println("The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs()));             //执行目标方法             result = pjd.proceed();             //返回通知             System.out.println("The method " + methodName + " ends with " + result);         } catch (Throwable e) {
            //异常通知             System.out.println("The method " + methodName + " occurs exception:" + e);             throw new RuntimeException(e);         }         //后置通知         System.out.println("The method " + methodName + " ends");                  return result;     }     */ }

3:配置文件中配置上使用注解和AOP

 ***:小知识:先执行哪个切面类

@Order(1)  值越小越先 执行

 4:基于xml文件配置的方式

 

转载于:https://www.cnblogs.com/bulrush/p/7912356.html

你可能感兴趣的文章
idea搭建tocmat
查看>>
NYOJ-626-intersection set(二分查找)
查看>>
项目管理之路(1):初步踏入项目管理
查看>>
Java 中 静态方法与非静态方法的区别
查看>>
echarts饼图显示百分比
查看>>
JMS消息
查看>>
Jenkins+ProGet+Windows Batch搭建全自动的内部包(NuGet)打包和推送及管理平台
查看>>
php上传文件及头像预览
查看>>
大四java实习生的一些经历
查看>>
线程池的概念
查看>>
Oracle_Statspack性能诊断工具
查看>>
转获取sql维护的表关系
查看>>
Java 序列化
查看>>
Java 时间处理实例
查看>>
Java 多线程编程
查看>>
Java 数组实例
查看>>
mysql启动过程
查看>>
2017前端面试题总结
查看>>
Http GetPost网络请求
查看>>
SWIFT国际资金清算系统
查看>>