深入浅出讲解Spring框架中AOP及动态代理的应用
目录
- 一. Spring AOP
- 1. 传统问题:
- 2. 问题的解决策略:
- 3. AOP优点:
- 二. 动态代理
- 1.JDK动态代理
- 2. CGLIB代理
一. Spring AOP
面向切面编程(Aspect Oriented Programming,AOP)是软件编程思想发展到一定阶段的产物,是对面向对象编程(Object Oriented Programming,OOP)的有益补充, 目前已成为一种比较成熟的编程方式。AOP适用于具有横向逻辑的场所,如访问控制、事务管理、性能监测等。
1. 传统问题:
在传统的业务处理代码中,通常都会进行事务处理、日志记录等操作。虽然OOP可以通过组合或者继承的方式来达到代码的重用,但是比如实现日志记录时,代码还是会分散到不同的方法中。这样就会存在一个问题,如果想要关闭某个功能或者修改时,就必须要修改所有的相关方法。这不单单增加了开发人员的工作量,而且提高了代码的出错率。
2. 问题的解决策略:
为了解决这个问题,AOP思想随之产生。AOP采取横向抽取机制,将分散在各个方法中的重复代码提取出来,然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方。这种采用横向抽取机制的方式,是传统的OOP思想无法办到的,因为OOP只能实现父子关系的纵向的重用。虽然AOP是一种新的编程思想,却不是OOP的替代品,它只是OOP的延申和补充。
3. AOP优点:
AOP的使用让开发人员在编写业务逻辑时可以专心于核心业务,而不用过多地关注于其他业务逻辑的实现,这不但提高了开发效率,而且增强了代码的可维护性。
在AOP思想中,类于切面的关系如下图所示。我们可以看出,通过Aspect(切面)分别在Class1和Class2的方法中加入了事务、日志、权限和异常等功能。
二. 动态代理
通过学习我们知道了AOP中的代理就是由AOP框架动态生成的一个对象,该对象可以作为目标对象使用,对于面向切面编程,简单地说,就是在不改变原程序的基础上为代码段增加新的功能,对代码段进行增强处理。它的设计思想来源于代理设计模式,通常情况下调用对象的方法如下图。
在代理模式中可以为该对象设置一个代理对象,代理对象为function()提供一个代理方法,当通过代理对象的function()方法调用原对象的function()方法时,就可以在代理方法中添加新的功能,即增强处理。增强的功能既可以插到原对象的function()前面,也可以插到其后面(如虚线)
1.JDK动态代理
JDK动态代理是通过java.lang.reflect.Proxy类来实现的,可以调用Proxy类的newProxyInstance()方法来创建代理对象。对于使用业务接口的类,Spring框架会默认使用JDK动态代理来实现AOP。通过一个案例来演示。
1. UserDao.java
package dao; public interface UserDao { public void addUserDao(); public void deleteUser(); }
2. UserDaoImpl.java
package dao; public class UserDaoImpl implements UserDao{ @Override public void addUserDao() { System.out.println("添加用户"); } @Override public void deleteUser() { System.out.println("删除用户"); } }
3. MyAspect.java
package aspect; public class MyAspect { public void check_permission(){ System.out.println("----模拟检查访问----"); } public void log(){ System.out.println("----模拟记录日记----"); } }
4. JdkProxy.java
package jdk; import aspect.MyAspect; import dao.UserDao; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * Jdk代理类 */ public class JdkProxy implements InvocationHandler { //声明目标类接口 private UserDao userdao; // 创建代理方法 public Object createProxy(UserDao userdao){ this.userdao=userdao; //类加载器 ClassLoader classLoader=JdkProxy.class.getClassLoader(); //被代理对象实现的所有接口 Class[] clazz=userdao.getClass().getInterfaces(); //使用代理类进行增强,返回的是代理后的对象 return Proxy.newProxyInstance(classLoader,clazz,this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //声明切面 MyAspect myAspect=new MyAspect(); //前增强 myAspect.check_permission(); //在目标上调用方法,并传入参数 Object obj=method.invoke(userdao,args); //后增强 myAspect.log(); return obj; } }
5. Test.java
@Test public void shouldAnswerWithTrue() { JdkProxy jdkProxy=new JdkProxy(); UserDao userDao=new UserDaoImpl(); UserDao userDao1=(UserDao) jdkProxy.createProxy(userDao); userDao1.addUserDao(); System.out.println("\n-----------------------------分割线------------------------------------\n"); userDao1.deleteUser(); }
结果:
2. CGLIB代理
JDK 动态代理的使用非常简单,但它具有一定的局限性(使用动态代理的对象必须实现一个或多个接口)如果要对没有实现接口的类进行代理,那么可以使用CGLIB代理。
CGLIB(Code Generation Library)是一个高性能开源的代码生成包,它采用非常底层的字节码技术,对指定的目标类生成一个子类,并对子类进行增强。在Spring框架的核心包中已经集成了CGLIB所需要的包,所以开发中不需要另外导入jar包。
1. BookDao.java
package dao; public class BookDao { public void addBook(){ System.out.println("添加书本"); } public void deleteBook(){ System.out.println("删除书本"); } }
2. CglibProxy.java
package jdk; import aspect.MyAspect; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class CglibProxy implements MethodInterceptor { //代理方法 public Object createProxy(Object target){ Enhancer enhancer=new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { MyAspect myAspect=new MyAspect(); myAspect.check_permission(); Object o1=methodProxy.invokeSuper(proxy,args); myAspect.log(); return o1; } }
结果:
到此这篇关于深入浅出讲解Spring框架中AOP及动态代理的应用的文章就介绍到这了,更多相关Spring AOP及动态代理内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!