学习Java框架的笔记(Spring AOP)简介、动态代理、基于代理类的AOP实现、AspectJ开发
1.Spring AOP简介
1.1 什么是AOP
- AOP的全称是:Aspect - Oriented - Programming 即 面向切面编程(也称之为:面向方面编程)
- 在传统的业务处理代码中,通常都会进行事物处理、日志记录等操作。如果使用传统的OOP方式(通过组合或者继承)的方式来达到代码的重用,会使同样的代码分散到各个方法中。如果想要关闭这个操作(功能),就需要对相关的所有方法进行修改,十分麻烦,增加了代码的耦合性,不灵活,不符合(高内聚低耦合的要求)。
- 为解决这一问题,AOP思想出现,AOP采用横向抽取机制,将分散在各个方法中的代码提取出来(例如日志记录,需要在main方法的前后进行执行),然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方,这种就是采用横向抽取机制的方式。AOP是一种新的编程思想,不是OOP的替代品,它是OOP的延伸和补充。
- 目前最流行的AOP框架有两个,Spring AOP 和 AspectJ。
- 区别:
-
Spring AOP: 使用纯Java实现,不需要专门的编译过程和类加载器,在运行期间通过代理方式想目标类织入增强代码(扩充的功能代码)。
-
AspectJ: 是基于Java语言的AOP框架,从Spring 2.0开始,Spring AOP 引用了对AspectJ的支持,AspectJ扩展了Java语言,提供了 一个专门的编译器,在编译时提供横向代码的织入。
1.2 AOP术语
AOP术语:包括Aspect(切面)、Joinpoint(连接点)、Pointcut(切入点)、Advice(通知/增强处理)、Target Object(目标对象)、 Proxy(代理)、Weaving(织入)
- Aspect(切面):通常指封装的用于横向插入系统功能(事务,日志)的类。该类要被Spring容器识别为切面,需要在配置文件中通过< bean >元素指定。
- Joinpoint(连接点):在程序执行过程中的某个阶段点,实际上是对象的一个操作(例如:方法的调用或者异常的抛出)。
- Pointcut(切入点):切面与程序流程的交叉点,即那些需要处理的连接点。在通常程序中,切入点指的是类/方法名。(连接点包涵切入点且更多)。
- Advice(通知/增强处理):AOP框架在特定的切入点执行的增强处理,即在定义好的切入点执行的代码。
- Target Object(目标对象):是指所有被通知的对象,也称为被增强对象。如果AOP框架采用的是动态的AOP实现,那么该对象就是一个被代理对象。
- Proxy(代理):将通知应用到目标对象之后被动态创建的对象。
- Weaving(织入):将切面代码插入到目标对象上,从而生成代理对象的过程。
2. 动态代理
AOP中的代理就是由AOP框架动态生成的 一个对象,该对象可以作为目标对象使用。增强方法的意思就是:调用切面类,将切面类中的方法加到目标类中,扩充其中方法数量,就是增强方法。
2.1 JDK动态代理
例图:
代码:
(1)创建一个web项目,导入Spring框架所需要的JAR包到项目的lib目录下,并发布到类路径下。
(2)在src目录下:创建一个com.itheima.jdk包,在该包下创建接口UserDao ,并在其中编写添加和删除的方法
package com.itheima.jdk; public interface UserDao { public void addUser(); //添加 public void deleteUser(); //删除 }
(3)在com.itheima.jdk包中,创建UserDao接口的实现类UserDaoImpl ,分别实现接口中的方法。
package com.itheima.jdk; import org.springframework.stereotype.Repository; // 目标类(被代理对象:房主) @Repository("userDao") public class UserDaoImpl implements UserDao { public void addUser() { System.out.println("添加用户"); } public void deleteUser() { System.out.println("删除用户"); } }
(4)在src目录下,创建一个com.itheima.aspect包,并且在该包下创建切面类MyAspect ,在该类中定义一个模拟权限检查的方法,这两个方法就表示切面中的通知
package com.itheima.aspect; //切面类:可以存在多个通知Advice(即增强的方法) public class MyAspect { public void check_Permissions(){ System.out.println("模拟检查权限..."); } public void log(){ System.out.println("模拟记录日志..."); } }
(5)在com.itheima.jdk包下,创建代理类JdkProxy,该类需要实现InvocationHandler接口,并编写代理方法。在代理方法中,需要通过Proxy类实现动态代理
反射:通过对象名/类名,获取class文件,获取该类的所有
通过对象: .getClass ; 通过类名: .class
package com.itheima.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import com.itheima.aspect.MyAspect; /** * JDK代理类 */ public class JdkProxy implements InvocationHandler{ //InvocationHandler接口实现invoke()方法 // 声明目标类接口(房主) private UserDao userDao; // 创建代理方法 public Object createProxy(UserDao userDao) { this.userDao = userDao; // 1.类加载器(通过类名反射得到当前类.getClassLoader()再获取类加载器上的容器) ClassLoader classLoader = JdkProxy.class.getClassLoader(); // 2.被代理对象实现的所有接口,通过userDao对象实例,通过反射getInterfaces获取该类所有方法 Class[] clazz = userDao.getClass().getInterfaces(); // 3.使用代理类,进行增强,返回的是代理后的对象(动态生成一个代理类,参数:一个加载器,userDao的所有方法,该类) return Proxy.newProxyInstance(classLoader,clazz,this); } /* * 所有动态代理类的方法调用,都会交由invoke()方法去处理 * 执行被代理对象中的方法的反射 * proxy 被代理后的对象 * method 将要被执行的方法信息(反射) * args 执行方法时需要的参数,几个方法 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 声明切面 MyAspect myAspect = new MyAspect(); // 前增强 myAspect.check_Permissions(); // 在目标类上调用方法,并传入参数 Object obj = method.invoke(userDao, args); // 后增强 myAspect.log(); return obj; } }
(6)在com.itheima.jdk包下,创建测试类JdkTest,在该类中的main方法中创建代理对象和目标对象,然后从代理对象中获取目标对象userDao增强后的对象,最后调用该对象的添加个删除方法
package com.itheima.jdk; public class JdkTest{ public static void main(String[] args) { // 创建代理对象 JdkProxy jdkProxy = new JdkProxy(); // 创建目标对象 UserDao userDao= new UserDaoImpl(); // 从代理对象中获取增强后的目标对象 UserDao userDao1 = (UserDao) jdkProxy.createProxy(userDao); // 执行方法 userDao1.addUser(); userDao1.deleteUser(); } }
实验结果截图:
2.2 CGLIB代理
相比于JDK动态代理而言,CGLIB代理有一个最大优势是:JDK动态代理对象必须实现一个或多个接口。而CGLIB代理可以对没有接口的类进行代理。(1)同上UserDao目标类一样:
package com.itheima.cglib; //目标类 public class UserDao { public void addUser() { System.out.println("添加用户"); } public void deleteUser() { System.out.println("删除用户"); } }
(2)在com.itheima.cglib包中,创建代理类CglibProxy ,该代理类需要实现MethodInterceptor接口,并实现接口中的intercept()方法
package com.itheima.cglib; import java.lang.reflect.Method; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import com.itheima.aspect.MyAspect; // 代理类 public class CglibProxy implements MethodInterceptor{ // 代理方法 public Object createProxy(Object target) { // 创建一个动态类对象 Enhancer enhancer = new Enhancer(); // 确定需要增强的类,设置其父类 enhancer.setSuperclass(target.getClass()); // 添加回调函数(自己调用自己) enhancer.setCallback(this); //this代表的就是代理类CglibProxy 本身 // 返回创建的代理类 return enhancer.create(); } /** * proxy CGlib根据指定父类生成的代理对象 * method 拦截的方法 * args 拦截方法的参数数组 * methodProxy 方法的代理对象,用于执行父类的方法 */ @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { // 创建切面类对象 MyAspect myAspect = new MyAspect(); // 前增强 myAspect.check_Permissions(); // 目标方法执行 Object obj = methodProxy.invokeSuper(proxy, args); // 后增强 myAspect.log(); return obj; } }
(3)在com.itheima.cglib包中,创建测试类CglibTest 。
package com.itheima.cglib; // 测试类 public class CglibTest { public static void main(String[] args) { // 创建代理对象 CglibProxy cglibProxy = new CglibProxy(); // 创建目标对象 UserDao userDao = new UserDao(); // 获取增强后的目标对象 UserDao userDao1 = (UserDao)cglibProxy.createProxy(userDao); // 执行方法 userDao1.addUser(); userDao1.deleteUser(); } }
实验结果截图:
- 学习Java框架的笔记(Spring AOP)基于代理类的AOP实现、AspectJ开发(2)、ApectJ注解式声明
- Spring学习笔记:使用代理实现AOP
- spring aop学习7:Cglib动态代理(基于继承代理)
- 学习笔记之springAOP的aspectJ实现注意点总结
- SpringAOP学习笔记(4)CGLIB动态代理
- spring学习笔记(7)AOP前夕[2]CGLib动态代理实例解析
- Spring AOP之---基于JDK动态代理和CGLib动态代理的AOP实现
- Spring4学习笔记-AOP前传之动态代理
- spring 学习笔记 使用aspectj开发aop
- [Spring学习笔记 4 ] AOP 概念原理以及java动态代理
- [Spring学习笔记 4 ] AOP 概念原理以及java动态代理
- Spring学习-22:Spring的AOP:基于AspectJ的XML配置方式开发
- [原创]java WEB学习笔记104:Spring学习---AOP 前奏,通过一个问题引入动态代理
- Spring学习-21:Spring的AOP:基于AspectJ的注解开发
- Spring学习笔记之aop动态代理(3)
- Spring 4 学习笔记4:Java动态代理(Spring AOP原理)
- 学习《spring 3.x企业应用开发实战》之基于@AspectJ和Schema的AOP
- 学习笔记--代理与AOP及实现类似SPRING的可配置的AOP框架
- Spring4学习笔记-AOP前传之动态代理
- Spring中Aop的实现方式之一(基于动态代理)