微服务架构(SpringCloudAlibaba)-->针对业务层面的拆分--->增加了系统处理的复杂性(服务治理)--->服务网格(istio,再服务忘了架构基础之上,将业务实现和服务治理进行了拆分。) 如果应用架构又改变了--> 微服务架构技术就不吃香了--->不变的东西(架构思想,强大的继承【数据结构与算法,JVM,并发编程,Netty,MySql】)
业务层存在的问题:
public class UserServiceImpl{ public void saveUser(){ // C 程序员:⽇志监控 // B 程序员:开启事务--系统逻辑 // A 程序员:编写业务逻辑代码--程序员更应该关注业务的实现,⽽不需要关⼼系统逻辑 // B 程序员:关闭事务--系统逻辑 } } public class OrderServiceImpl{ public void saveOrder(){ // 开启事务 // 编写业务逻辑代码 // 关闭事务 } }
需要改善的地方:
Joinpoint(连接点)
所谓连接到是指哪些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
Pointcut(切入点)
所谓切入点是指我们要对哪些Joinpoint进行拦截的定义
Advice(通知/增强)
所谓通知是指拦截到Joinpoint之后所要作的事情就是通知,通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切莫要完成的功能)
Introduction(引介)
引介是一种特殊的通知在不修改类代码的前提下,Introduction可以在运行期间为类动态地添加一些方法或Field
Target(目标对象)
代理的目标对象
Weaving(织入)
是指把增强应用到目标对象来创建新的代理对象的过程
Proxy(代理)
一个类被AOP织入增强后,就产生一个结果代理类
Aspect(切面)
是切入点和通知的结合。以后可以编写和配置的
Advisor(通知面,顾问)
和Aspect很相似
目标对象必须实现接口
// JDK代理对象⼯⼚&代理对象⽅法调⽤处理器 public class JDKProxyFactory implements InvocationHandler { // ⽬标对象的引⽤ private Object target; // 通过构造⽅法将⽬标对象注⼊到代理对象中 public JDKProxyFactory(Object target) { super(); this.target = target; } /** * @return */ public Object getProxy() { // 如何⽣成⼀个代理类呢? // 1、编写源⽂件 // 2、编译源⽂件为class⽂件 // 3、将class⽂件加载到JVM中(ClassLoader) // 4、将class⽂件对应的对象进⾏实例化(反射) // Proxy是JDK中的API类 // 第⼀个参数:⽬标对象的类加载器 // 第⼆个参数:⽬标对象的接⼝ // 第⼆个参数:代理对象的执⾏处理器 Object object = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); return object; } /** * 代理对象会执⾏的⽅法 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Method method2 = target.getClass().getMethod("saveUser", null); Method method3 = Class.forName("com.sun.proxy.$Proxy4").getMethod("saveUser", null); System.out.println("⽬标对象的⽅法:" + method2.toString()); System.out.println("⽬标接⼝的⽅法:" + method.toString()); System.out.println("代理对象的⽅法:" + method3.toString()); System.out.println("这是jdk的代理⽅法"); // 下⾯的代码,是反射中的API⽤法 // 该⾏代码,实际调⽤的是[⽬标对象]的⽅法 // 利⽤反射,调⽤[⽬标对象]的⽅法 Object returnValue = method.invoke(target, args); return returnValue; } }
public class CgLibProxyFactory implements MethodInterceptor { /** * @param clazz * @return */ public Object getProxyByCgLib(Class clazz) { // 创建增强器 Enhancer enhancer = new Enhancer(); // 设置需要增强的类的类对象 enhancer.setSuperclass(clazz); // 设置回调函数 enhancer.setCallback(this); // 获取增强之后的代理对象 return enhancer.create(); } /*** * Object proxy:这是代理对象,也就是[⽬标对象]的⼦类 * Method method:[⽬标对象]的⽅法 * Object[] arg:参数 * MethodProxy methodProxy:代理对象的⽅法 */ @Override public Object intercept(Object proxy, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable { // 因为代理对象是⽬标对象的⼦类 // 该⾏代码,实际调⽤的是⽗类⽬标对象的⽅法 System.out.println("这是cglib的代理⽅法"); // 通过调⽤⼦类[代理类]的invokeSuper⽅法,去实际调⽤[⽬标对象]的⽅法 Object returnValue = methodProxy.invokeSuper(proxy, arg); // 代理对象调⽤代理对象的invokeSuper⽅法,⽽invokeSuper⽅法会去调⽤⽬标类的invoke⽅ 法完成⽬标对象的调⽤ return returnValue; } }
ASM API使用
ClassWriter classWriter = new ClassWriter(0); classWriter.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, className, null, "java/lang/Object", null); MethodVisitor initVisitor = classWriter.visitMethod(Opcodes.ACC_PUBLIC, " <init>", "()V", null, null); initVisitor.visitCode();//访问开始 initVisitor.visitVarInsn(Opcodes.ALOAD, 0);//this指针⼊栈 initVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", " <init>", "()V");//调⽤构造函数 initVisitor.visitInsn(Opcodes.RETURN); initVisitor.visitMaxs(1, 1);//设置栈⻓、本地变量数
- 前置通知:org.springframework.aop.MethodBeforeAdvice - 后置通知:org.springframework.aop.AfterReturningAdvice - 环绕通知:org.aopalliance.intercept.MethodInterceptor - 异常通知:org.springframework.aop.ThrowsAdvice
其实就是指的Spring+AspectJ整合,不过Spring以及将AspectJ收录到自身的框架中了,并且底层织入依然是采取的动态织入方式。
切入点表达式的格式:
execution([修饰符]返回值类型 包名.类名.方法名(参数))
表达式格式说明:
execution:必须要
修饰符:可省略
返回值类型:必须要,但是可以使用*通配符
包名:
** 多级包之间使⽤.分割 ** 包名可以使⽤*代替,多级包名可以使⽤多个*代替 ** 如果想省略中间的包名可以使⽤ ..
类名
** 可以使⽤*代替 ** 也可以写成*DaoImpl
方法名:
** 也可以使⽤*好代替 ** 也可以写成add*
参数
** 参数使⽤*代替 ** 如果有多个参数,可以使⽤ ..代替
通知类型(五种):前置通知,后置通知,最终通知,环绕通知,异常抛出通知。
前置通知:
* 执⾏时机:⽬标对象⽅法之前执⾏通知 * 配置⽂件:<aop:before method="before" pointcut-ref="myPointcut"/> * 应⽤场景:⽅法开始时可以进⾏校验
后置通知:
* 执⾏时机:⽬标对象⽅法之后执⾏通知,有异常则不执⾏了 * 配置⽂件:<aop:after-returning method="afterReturning" pointcutref="myPointcut"/> * 应⽤场景:可以修改⽅法的返回值
最终通知:
* 执⾏时机:⽬标对象⽅法之后执⾏通知,有没有异常都会执⾏ * 配置⽂件:<aop:after method="after" pointcut-ref="myPointcut"/> * 应⽤场景:例如像释放资源
环绕通知:
* 执⾏时机:⽬标对象⽅法之前和之后都会执⾏。 * 配置⽂件:<aop:around method="around" pointcut-ref="myPointcut"/> * 应⽤场景:事务、统计代码执⾏时机
异常抛出通知:
* 执⾏时机:在抛出异常后通知 * 配置⽂件:<aop:after-throwing method=" afterThrowing " pointcutref="myPointcut"/> * 应⽤场景:包装异常
编写切面类(注意不是通知类,因为该类中可以指的切入点)
环绕通知注解
@Around
作⽤: 把当前⽅法看成是环绕通知。属性: value: ⽤于指定切⼊点表达式,还可以指定切⼊点表达式的引⽤。
定义通用切入点
使用@PointCut注解再切面类中定义一个通用的切入点,其他通知可以引用该切入点
@Configuration @ComponentScan(basePackages="com.kkb") @EnableAspectJAutoProxy public class SpringConfiguration { }
其实每个模式名称就表明了该模式的作用,戴爱玲模式就是多一个代理类出来替原对象进行一些操作。代理又分为动态代理和静态代理。
比如租房子找中介
静态代理的重点:
静态代理的缺点:
如果已有的方法再使用的时候需要对原有的方法进行改进,此时有俩种办法:
使用代理模式,可以将功能划分的更加清晰,有助于后期维护!
动态代理再编译期间,不需要为源类去手动编写一个代理类
只会再运行期间,去为源对象产生一个代理对象。
JDK动代理和Cglib动态代理的区别
1.JDK动态代理是Java⾃带的,cglib动态代理是第三⽅jar包提供的。 2.JDK动态代理是针对【拥有接⼝的⽬标类】进⾏动态代理的,⽽Cglib是【⾮final类】都可以进⾏动态 代理。但是Spring【优先使⽤JDK动态代理】。 3.JDK动态代理实现的逻辑是【⽬标类】和【代理类】都【实现同⼀个接⼝】,⽬标类和代理类【是平级 的】。⽽Cglib动态代理实现的逻辑是给【⽬标类】⽣个孩⼦(⼦类,也就是【代理类】),【⽬标类】和 【代理类】是⽗⼦继承关系】。 4.JDK动态代理在早期的JDK1.6左右性能⽐cglib差,但是在JDK1.8以后cglib和jdk的动态代理性能基 本上差不多。反⽽jdk动态代理性能更加的优越