标签:info int 用户 面向切面 总经理 create 新建 类加载 system
Spring AOP的2种代理
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是通过代理(proxy)实现的AOP。有2种代理方式:JDK动态代理、CGLIB代理。
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(业务本身)中的方法。
因为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代理不需要目标类实现接口。
标签:info int 用户 面向切面 总经理 create 新建 类加载 system
原文地址:https://www.cnblogs.com/chy18883701161/p/11135435.html