Spring AOP

2019-08-16 09:47:47来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

Spring AOP

 

目录

AOP简介

Spring  AOP的2种代理

  • JDK动态代理
  • CGLIB代理

 

 

 

AOP简介

AOP全称Aspect-Oriented  Programming,即面向切面编程,它是面向对象编程(OOP)的一种补充。

 

在通常的业务处理中,都会进行事务处理、日志记录等操作,比如:

 1 class  User{
 2     public void addUser(){
 3         ......  //添加用户
 4         ....... //记录一条日志:xxx时间添加xxx用户,操作者:xxx,操作结果:xxx
 5     }
 6 
 7     public  void  alterUser(){
 8         .......  //修改用户
 9         ........//记录一条日志:xxx时间修改xxx用户,操作者:xxx,操作结果:xxx
10     }
11 
12     public void  deleteUser(){
13         .......//删除用户
14         .......//记录一条日志:xxx时间删除xxx用户,操作者:xxx,操作结果:xxx
15 }

这是一个操作用户的类,是对用户的抽象,日志操作和用户操作其实没有半毛钱关系,上面的抽象并不好,把用户操作和日志操作杂糅在一起,应该把日志操作分离出去,这样才符合OOP的编程思想。

而且后期不好维护、升级,比如后面要修改日志操作,你找到User类,在addUser()中一部分是用户操作,一部分是日志操作,你要先找到哪些是日志操作,然后改。后面的方法也是如此,很繁琐。

 

AOP解决了此问题。AOP是一种新的编程思想,是OOP的一种补充。OOP专心负责核心业务,AOP负责其它杂七杂八的业务。

OOP好比是经理,AOP好比是助理。原先所有事儿,什么批文件、见客户、通知下级来开会、向下级传达指示,所有事儿都是自己做,很繁琐,搞得精疲力竭,还容易出问题。

现在招了助理AOP,总经理OOP可以专心处理核心的业务,批示下文件、见见客户就行了。传递指示、通知下级开会,这些事儿助理AOP来做。分工明确,效率

高很多。

 

 

这些操作往往可以被多个类使用的,所以叫做一个切面(Aspect)。

 

目前最流行的AOP框架有2个:Spring  AOP和AspectJ。

 

 

 

 

Spring  AOP

在Spring AOP中,spring是通过代理(proxy)实现的AOP。有2种代理方式:JDK动态代理、CGLIB代理。

 

JDK动态代理

1、新建包jdk_proxy,用来写代理类、被代理类。包下新建UserInterface接口

1 public interface UserInterface {
2     public void addUser();
3     public void alterUser();
4     public void deleteUser();
5 }

 

 

包下新建一个实现类User

 1 public class User implements UserInterface {
 2     @Override
 3     public void addUser() {
 4         //模拟添加用户
 5         System.out.println("正在添加用户");
 6         System.out.println("添加用户成功");
 7     }
 8 
 9     @Override
10     public void alterUser() {
11         //模拟修改用户信息
12         System.out.println("正在修改用户信息");
13         System.out.println("修改用户信息成功");
14     }
15 
16     @Override
17     public void deleteUser() {
18         //模拟删除用户
19         System.out.println("正在删除用户");
20         System.out.println("删除用户成功");
21     }
22 }

 

这些是要被代理的类。

 

 

2、新建包aspect,用来写切面中要使用方法(类)。包下新建类MyAspect

 1 public class MyAspect {
 2     //模拟检查权限
 3     public boolean checkPermission(){
 4         System.out.println("正在检查权限");
 5         System.out.println("权限已够");
 6         return true;
 7     }
 8 
 9     //模拟日志
10     public void log(){
11         System.out.println("正在写入日志");
12         System.out.println("xxx时间,xxx进行xxx操作,操作结果:xxx");
13         System.out.println("日志写入完毕");
14     }
15 }

 

 

 

3、在jdk_proxy包下,新建JdkProxy类,要实现InvocationHandler接口(只有invoke()方法)

 1 public class JdkProxy implements InvocationHandler {
 2     //声明目标接口的实例
 3     private UserInterface user;
 4     
 5     //创建代理方法,参数是目标接口的实例
 6     public Object createProxy(UserInterface user){
 7         this.user=user;   //初始化目标接口实例
 8 
 9         ClassLoader classLoader=JdkProxy.class.getClassLoader();  //获取当前类的类加载器,当前类类名.class.getClassLoader()
10         Class[] classArr=user.getClass().getInterfaces();  //获取目标接口实例实现的全部接口
11 
12         //参数:当前类的类加载器,目标接口实例实现的所有接口,当前类的实例
13         return Proxy.newProxyInstance(classLoader,classArr,this);
14     }
15 
16     @Override
17     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
18         //声明切面
19         MyAspect myAspect=new MyAspect();
20 
21         //前增强,执行切面中的方法,在执行目标类中的方法之前做一些操作,比如检查权限。根据需要选用。
22         myAspect.checkPermission();
23 
24         //执行目标类中的方法。比如addUser()。第一个参数目标对象,第二个是固定的
25         Object object=method.invoke(user,args);
26 
27         //后增强。执行切面中的方法,在执行目标类中的方法之后做一些操作,比如记录日志。根据需要选用。
28         myAspect.log();
29 
30         return object;
31     }
32 }

 

这是代理类,用来代理User类/UserInterface接口。

 

 

4、 新建一个test包,用来写测试类。包下新建类Test

 1 public class Test {
 2     public static void main(String[] args) {
 3         //JdkProxy的实例
 4         JdkProxy jdkProxy=new JdkProxy();
 5 
 6         //创建目标对象
 7         UserInterface user=new User();
 8 
 9         //通过JdkProxy类的实例动态创建user的代理,因为返回值是Object,需要强制类型转换,必须用目标接口转换,不能用实现类转换
10         UserInterface userProxy=(UserInterface) jdkProxy.createProxy(user);
11 
12         //通过代理调用方法,会自动调用OOP、AOP中的相关方法。
13         userProxy.addUser();
14     }
15 }

 

 

5、运行,看到控制台输出如下

正在检查权限
权限已够
正在添加用户
添加用户成功
正在写入日志
xxx时间,xxx进行xxx操作,操作结果:xxx
日志写入完毕

已自动调用AOP(前增强+后增强)、OOP(业务本身)中的方法。

 

 

 

模型分析

 

 

AOP术语

  • Aspect(切面):用来写AOP中要用的方法,比如上例中的MyAspect类。
  • Pointcut(切入点):AOP、OOP交汇处,比如addUser()、alterUser()、deleteUser(),这三个方法是OOP中的方法,但使用时还会调用AOP中检查权限、记录日志的方法,这三个方法就是AOP切入OOP的切入点。
  • Joinpoint(连接点):即切入点+AOP处理的点,比如checkPermission()、addUser()、log()就是三个连接点。
  • Advice(通知/增强):英文意为建议,即做一些其他操作。比如前增强checkPermission()、后增强log()
  • Target  Object(目标对象):被代理的对象,比如UserInterface接口/User类的实例
  • Proxy(代理):即上例的userProxy
  • Weaving(织入):将AOP植入到OOP中,比如上例的JdkProxy类。

 

 

 

 

CGLIB代理

因为JDK动态代理的JdkProxy类中的createProxy()方法中 Class[] classArr=user.getClass().getInterfaces(); //获取目标接口实例实现的全部接口 ,要用到目标对象的所实现的全部接口,就是说被代理的OOP的核心业务类必须要实现接口。

如果被代理的类没有实现接口,则可以使用CGLIB代理。

 

1、新建一个cglib包,用来写代理类、被代理类。包下新建User类(被代理类),不必实现接口

 1 public class User{
 2     public void addUser() {
 3         //模拟添加用户
 4         System.out.println("正在添加用户");
 5         System.out.println("添加用户成功");
 6     }
 7 
 8     public void alterUser() {
 9         //模拟修改用户信息
10         System.out.println("正在修改用户信息");
11         System.out.println("修改用户信息成功");
12     }
13 
14     public void deleteUser() {
15         //模拟删除用户
16         System.out.println("正在删除用户");
17         System.out.println("删除用户成功");
18     }
19 }

 

 

 

2、新建包aspect,包下新建切面类MyAspect

 1 public class MyAspect {
 2     //模拟检查权限
 3     public boolean checkPermission(){
 4         System.out.println("正在检查权限");
 5         System.out.println("权限已够");
 6         return true;
 7     }
 8 
 9     //模拟日志
10     public void log(){
11         System.out.println("正在写入日志");
12         System.out.println("xxx时间,xxx进行xxx操作,操作结果:xxx");
13         System.out.println("日志写入完毕");
14     }
15 }

 

 

 

3、在cglib包下新建CglibProxy类(代理类),需实现MethodInterceptor接口(只有intercept()方法)。注意是org.springframework.cglib.proxy.MethodInterceptor接口,不是其他包下的MethodInterceptor接口。

 1 public class CglibProxy implements MethodInterceptor {
 2     //创建代理,参数是Object类型
 3     public Object createProxy(Object target){
 4         Enhancer enhancer=new Enhancer();   //创建一个动态类对象
 5         enhancer.setSuperclass(target.getClass());  //将这个动态类对象的父类/基类设置为目标类(需要增强的类)
 6         enhancer.setCallback(this);  //设置回调
 7         return  enhancer.create();  //返回创建的代理
 8     }
 9 
10     @Override
11     public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
12         //创建切面实例
13         MyAspect myAspect=new MyAspect();
14 
15         //前增强
16         myAspect.checkPermission();
17 
18         //执行目标方法,参数:形参表的第一个参数、第三个参数
19         Object object=methodProxy.invokeSuper(o,objects);
20 
21         //后增强
22         myAspect.log();
23 
24         //返回代理对象
25         return object;
26     }
27 }

 

 

 

4、新建包test,包下新建测试类Test

 1 public class Test {
 2     public static void main(String[] args) {
 3         //创建CglibProxy的实例
 4         CglibProxy cglibProxy=new CglibProxy();
 5 
 6         //创建目标对象
 7         User user=new User();
 8 
 9         //通过CglibProxy类的实例创建user的代理,因为返回值是Object,需要强制类型转换,
10         User userProxy=(User)cglibProxy.createProxy(user);
11 
12         //通过代理调用方法,会自动调用OOP、AOP中的相关方法。
13         userProxy.addUser();
14     }
15 }

 

 

 

5、运行,控制台输出如下

正在检查权限
权限已够
正在添加用户
添加用户成功
正在写入日志
xxx时间,xxx进行xxx操作,操作结果:xxx
日志写入完毕

 

 

 

说明

  • JDK动态代理需要目标类(被代理的类)实现接口,CGLIB代理不需要目标类实现接口。
  • 需要spring-aop.jar的支持(Spring自带的)。

 


原文链接:https://www.cnblogs.com/chy18883701161/p/11135435.html
如有疑问请与原作者联系

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:Java 反射机制 初探*

下一篇:spring boot udp或者tcp接收数据