1 aop是什么
java的核心思想是面向对象,aop是面向切面编程.是对面向对象的一个补充,简单通俗的理解下aop,假设我们上楼梯,我的目标是三楼,我直接朝我的三楼直接过去,但是我可以在二楼的时候去朋友那里玩下,坐下其他的,然后再去三楼
这也不会影响我们的目标去三楼,那么去朋友那里玩,相当于增加的生活的乐趣去那里玩.相当于增强了我们的活动.
那么aop可以做啥呢,可以进行日志记录,可以进行事务管理,可以进行安全控制,可以进行异常处理,可以进行性能统计
2 理解几个关键字
切面
关注点形成的类,就叫切面(类)!
面向切面编程,就是指对很多功能都有的重复的代码抽取,再在运行的时候网业务方法上动态植入“切面类代码”
切点
执行目标对象方法,动态植入切面代码。
可以通过切入点表达式,指定拦截哪些类的哪些方法; 给指定的类在运行的时候植入切面类代码。
通知
在对象上面执行的内容
3 aop的实现原理:
aop的底层实现是代理模式加反射.
反射就不用多讲了,代理模式分为多种,静态代理和动态代理,动态代理面又分为jdk动态代理和cglib动态代理
代理模式的好处:可以防止对方得到我们真实的方法;
静态代理的实现方式:
package com.cxy.cyclicBarrier; /** * Created by Administrator on 2017/4/24. */ public interface IUserDao { void save(); }
package com.cxy.cyclicBarrier; /** * Created by Administrator on 2019/4/24. */ public class UserDao implements IUserDao { @Override public void save() { System.out.println("已经保存数据"); } }
代理类:
package com.cxy.cyclicBarrier; /** * Created by Administrator on 2019/4/24. */ public class UserDaoProxy implements IUserDao{ private IUserDao target; public UserDaoProxy(IUserDao iuserDao) { this.target = iuserDao; } public void save() { System.out.println("开启事物..."); target.save(); System.out.println("关闭事物..."); } public static void main(String[] args) { UserDao userDao=new UserDao(); UserDaoProxy userDaoProxy=new UserDaoProxy(userDao ); userDaoProxy.save(); } }
在最后可以看到执行结果:
结果分析:
静态代理:
由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
然后再看jdk动态代理:
package com.cxy.cyclicBarrier; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; // 每次生成动态代理类对象时,实现了InvocationHandler接口的调用处理器对象 public class InvocationHandlerImpl implements InvocationHandler { private Object target;// 这其实业务实现类对象,用来调用具体的业务方法 // 通过构造函数传入目标对象 public InvocationHandlerImpl(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; System.out.println("调用开始处理"); result = method.invoke(target, args); System.out.println("调用结束处理"); return result; } public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { // 被代理对象 IUserDao userDao = new UserDao(); InvocationHandlerImpl invocationHandlerImpl = new InvocationHandlerImpl(userDao); ClassLoader loader = userDao.getClass().getClassLoader(); Class<?>[] interfaces = userDao.getClass().getInterfaces(); // 主要装载器、一组接口及调用处理动态代理实例 IUserDao newProxyInstance = (IUserDao) Proxy.newProxyInstance(loader, interfaces, invocationHandlerImpl); newProxyInstance.save(); } }
结果分析:
jdk动态代理:
1. 通过实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(…);
2. 通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});
3. 通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
4. 通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
cglib代理:
package com.cxy.cyclicBarrier; import java.lang.reflect.Method; public class CglibProxy implements MethodInterceptor { private Object targetObject; // 这里的目标类型为Object,则可以接受任意一种参数作为被代理类,实现了动态代理 public Object getInstance(Object target) { // 设置需要创建子类的类 this.targetObject = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); return enhancer.create(); } public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("开启事物"); Object result = proxy.invoke(targetObject, args); System.out.println("关闭事物"); // 返回代理对象 return result; } public static void main(String[] args) { CglibProxy cglibProxy = new CglibProxy(); UserDao userDao = (UserDao) cglibProxy.getInstance(new UserDao()); userDao.save(); } }
执行结果:
在执行上面代码前需要引入asm包
原理:利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
4 区别比较:
CGLIB动态代理与JDK动态区别
java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
Spring中。
1)、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2)、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3)、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换
JDK动态代理只能对实现了接口的类生成代理,而不能针对类 。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。
因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。
5 aop的使用方式:
1) 注解方式:
<aop:aspectj-autoproxy></aop:aspectj-autoproxy> 开启事物注解权限 @Aspect 指定一个类为切面类 @Pointcut("execution(* com.xhz.service.UserService.add(..))") 指定切入点表达式 @Before("pointCut_()") 前置通知: 目标方法之前执行 @After("pointCut_()") 后置通知:目标方法之后执行(始终执行) @AfterReturning("pointCut_()") 返回后通知: 执行方法结束前执行(异常不执行) @AfterThrowing("pointCut_()") 异常通知: 出现异常时候执行 @Around("pointCut_()") 环绕通知: 环绕目标方法执行 @Component @Aspect public class AopLog { // 前置通知 @Before("execution(* com.cxy.service.UserService.add(..))") public void begin() { System.out.println("前置通知"); } // // 后置通知 @After("execution(* com.cxy.service.UserService.add(..))") public void commit() { System.out.println("后置通知"); } // 运行通知 @AfterReturning("execution(* com.cxy.service.UserService.add(..))") public void returning() { System.out.println("运行通知"); } // 异常通知 @AfterThrowing("execution(* com.cxy.service.UserService.add(..))") public void afterThrowing() { System.out.println("异常通知"); } // 环绕通知 @Around("execution(* com.cxy.service.UserService.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕通知开始"); proceedingJoinPoint.proceed(); System.out.println("环绕通知结束"); } }
2)xml方式:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- dao 实例 --> <bean id="userService" class="com.cxy.service.UserService"></bean> <!-- 切面类 --> <bean id="aop" class="com.cxy.aop2.AopLog2"></bean> <!-- Aop配置 --> <aop:config> <!-- 定义一个切入点表达式: 拦截哪些方法 --> <aop:pointcut expression="execution(* com.cxy.service.UserService.*(..))" id="pt" /> <!-- 切面 --> <aop:aspect ref="aop"> <!-- 环绕通知 --> <aop:around method="around" pointcut-ref="pt" /> <!-- 前置通知: 在目标方法调用前执行 --> <aop:before method="begin" pointcut-ref="pt" /> <!-- 后置通知: --> <aop:after method="after" pointcut-ref="pt" /> <!-- 返回后通知 --> <aop:after-returning method="afterReturning" pointcut-ref="pt" /> <!-- 异常通知 --> <aop:after-throwing method="afterThrowing" pointcut-ref="pt" /> </aop:aspect> </aop:config> </beans>
public class AopLog2 { // 前置通知 public void begin() { System.out.println("前置通知"); } // // 后置通知 public void commit() { System.out.println("后置通知"); } // 运行通知 public void returning() { System.out.println("运行通知"); } // 异常通知 public void afterThrowing() { System.out.println("异常通知"); } // 环绕通知 public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕通知开始"); proceedingJoinPoint.proceed(); System.out.println("环绕通知结束"); } }
今天的文章aop是怎么实现的_aop怎么实现的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/53316.html