当前位置: 首页 > news >正文

网络及建设公司网站商标注册查询网址

网络及建设公司网站,商标注册查询网址,qq在线网站代码生成,什么是网页设计规范文章目录系列文档索引一、认识AOP1、AOP的引入原因2、AOP常见使用场景日志场景统计场景安防场景性能场景3、AOP概念AOP 的概念Aspect 概念#xff08;切面#xff09;Join point 概念#xff08;连接点#xff09;Pointcut 概念#xff08;切入点#xff09;Advice 概念切面Join point 概念连接点Pointcut 概念切入点Advice 概念通知、动作Introduction 概念声明二、认识Spring AOP1、Spring AOP的设计目标来自官方文档2、Spring AOP的工作模式1代理模式① 静态代理② 动态代理2判断模式3拦截模式3、Spring AOP核心特性4、Spring AOP 编程模型注解驱动XML 配置驱动底层 API三、Spring AOP用到的代理方式1、JDK 动态代理实现1getProxyClass0方法3总结2、CGLIB 动态代理实现Spring中1代码实例2总结3、AspectJ 适配实现1AspectJ 语法2AspectJ 注解3总结4Spring AOP 和 AspectJ AOP 存在哪些区别未完待续参考资料系列文档索引 SpringAOP从入门到源码分析大全学好AOP这一篇就够了一 SpringAOP从入门到源码分析大全学好AOP这一篇就够了二 SpringAOP从入门到源码分析大全学好AOP这一篇就够了三 SpringAOP从入门到源码分析大全学好AOP这一篇就够了四 一、认识AOP 1、AOP的引入原因 java是静态语言一旦定义好结构不容易被修改而且传统的扩展方式都是通过继承和组合的方式组织新的类结构侵入性太强。 所以aop的出现就是为了解决这个问题就是让它方便的被修改从而对类的结构进行增强。 Java的Class类一旦被ClassLoader加载之后就会存储在永久代JDK8存储在元数据区要想对其进行修改可太难了使用ASM或者其他方式对开发者太不友好了而AOP正是完美解决这个问题AOP是不需要改变过去的类的结构进行扩展。 2、AOP常见使用场景 日志场景 诊断上下文如log4j或logback中的MDC。 记录方法入参出参等关键日志。 辅助信息如记录方法执行时间。 统计场景 记录方法调用次数、记录执行异常次数 数据抽样、数值累加 安防场景 熔断如Netflix Hystrix 限流和降级如Alibaba Sentinel 认证和授权如Spring Security 监控如JMX 性能场景 缓存如 Spring Cache 超时控制 3、AOP概念 AOP 的概念 1AspectJ中定义的AOP Aspect-oriented programming is a way of modularizing crosscutting concerns much like object-oriented programming is a way of modularizing common concerns. 面向切面编程是模块化横切关注点的一种方式就像面向对象编程是模块化公共关注点的一种方式一样。 2Spring中定义的AOP Aspect-oriented Programming (AOP) complements Object-oriented Programming (OOP) by providing another way of thinking about program structure. The key unit of modularity in OOP is the class, whereas in AOP the unit of modularity is the aspect. Aspects enable the modularization of concerns (such as transaction management) that cut across multiple types and objects. 面向切面编程(AOP)通过提供另一种思考程序结构的方式来补充面向对象编程(OOP)。在OOP中模块化的关键单位是类而在AOP中模块化的关键单位是切面。切面支持跨越多个类型和对象的关注点(例如事务管理)的模块化。 AOP是不需要改变过去的类的结构进行扩展如果使用OOP需要对过去的类的结构进行改变。 Aspect 概念切面 1AspectJ中定义的Aspect aspect are the unit of modularity for crosscutting concerns. They behave somewhat like Java classes, but may also include pointcuts, advice and inter-type declarations. 切面是横切关注点的模块化单位。它们的行为有点像Java类但也可能包括切入点、通知和类型间声明。 2Spring中定义的Aspect A modularization of a concern that cuts across multiple classes. 跨越多个类的关注点的模块化。 Join point 概念连接点 1AspectJ中定义的Join point A join point is a well-defined point in the program flow. A pointcut picks out certain join points and values at those points. 连接点是程序流中定义良好的点。切入点挑选出某些连接点和这些点上的值。 2Spring中定义的Join point A point during the execution of a program, such as the execution of a method or the handling of an exception. In Spring AOP, a join point always represents a method execution. 程序执行期间的一个点如方法的执行或异常的处理。在Spring AOP中一个连接点总是代表一个方法执行。 Pointcut 概念切入点 1AspectJ中定义的Pointcut pointcuts pick out certain join points in the program flow. 切入点挑选出程序流中的某些连接点。 2Spring中定义的Pointcut A predicate that matches join points. 匹配连接点的条件。 Advice 概念通知、动作 1AspectJ中定义的Advice So pointcuts pick out join points. But they don’t do anything apart from picking out join points. To actually implement crosscutting behavior, we use advice. Advice brings together a pointcut (to pick out join points) and a body of code (to run at each of those join points). 因此切入点挑选出连接点。但是除了选择连接点之外它们什么也不做。为了实际实现横切行为我们使用通知。通知将切入点(用于挑选连接点)和代码体(用于在每个连接点上运行)组合在一起。 2Spring中定义的Advice Action taken by an aspect at a particular join point. Different types of advice include “around”, “before” and “after” advice. Many AOP frameworks, including Spring, model an advice as an interceptor and maintain a chain of interceptors around the join point. 方面在特定连接点上采取的操作。不同类型的建议包括“前后”、“之前”和“之后”的动作。许多AOP框架包括Spring都将通知建模为一个拦截器并围绕连接点维护一个拦截器链。 Introduction 概念声明 1AspectJ中定义的Introduction Inter-type declarations in AspectJ are declarations that cut across classes and their hierarchies. They may declare members that cut across multiple classes, or change the inheritance relationship between classes. AspectJ中的类型间声明是跨越类及其层次结构的声明。它们可以声明跨越多个类的成员或者改变类之间的继承关系。 2Spring中定义的Introduction Declaring additional methods or fields on behalf of a type. Spring AOP lets you introduce new interfaces (and a corresponding implementation) to any advised object. 代表类型声明额外的方法或字段。Spring AOP允许您向任何被建议的对象引入新的接口(以及相应的实现)。 二、认识Spring AOP 1、Spring AOP的设计目标来自官方文档 Spring AOP’s approach to AOP differs from that of most other AOP frameworks. The aim is not to provide the most complete AOP implementation (although Spring AOP is quite capable). Rather, the aim is to provide a close integration between AOP implementation and Spring IoC, to help solve common problems in enterprise applications. Spring AOP实现AOP的方法不同于大多数其他AOP框架。其目的不是提供最完整的AOP实现(尽管Spring AOP相当能干)。相反其目的是提供AOP实现和Spring IOC之间的紧密集成以帮助解决企业应用程序中的常见问题。 Spring AOP never strives to compete with AspectJ to provide a comprehensive AOP solution. We believe that both proxy-based frameworks such as Spring AOP and full-blown frameworks such as AspectJ are valuable and that they are complementary, rather than in competition.Spring seamlessly integrates Spring AOP and IoC with AspectJ, to enable all uses of AOP within a consistent Spring-based application architecture. This integration does not affect the Spring AOP API or the AOP Alliance API. Spring AOP remains backwardcompatible. Spring AOP不与AspectJ竞争以提供全面的AOP解决方案。我们相信基于代理的框架(如Spring AOP)和成熟的框架(如AspectJ)都是有价值的它们是互补的而不是竞争的。Spring无缝地将Spring AOP和IOC与AspectJ集成在一起以支持在一致的基于Spring的应用程序架构中使用AOP。这个集成不会影响Spring AOP API或AOP Alliance API。Spring AOP仍然向后兼容。 实际上Spring AOP并未对编译期进行字节码的处理而是都在运行期间进行处理的通常都是用反射来实现的。 2、Spring AOP的工作模式 1代理模式 ① 静态代理 Java静态代理一般常用就是面向对象OOP继承和组合相结合的方式进行代理。 代码实例 public interface EchoService {String echo(String message) throws NullPointerException; }public class DefaultEchoService implements EchoService {Overridepublic String echo(String message) {return [ECHO] message;} }public class ProxyEchoService implements EchoService {private final EchoService echoService;public ProxyEchoService(EchoService echoService) {this.echoService echoService;}Overridepublic String echo(String message) {long startTime System.currentTimeMillis();String result echoService.echo(message);long costTime System.currentTimeMillis() - startTime;System.out.println(echo 方法执行的时间 costTime ms.);return result;} }public class StaticProxyDemo {public static void main(String[] args) {EchoService echoService new ProxyEchoService(new DefaultEchoService());echoService.echo(Hello,World);} }上面静态代理的实例就是基于接口需要实现同一个接口侵入性很强一般也称为装饰器模式。 ② 动态代理 Java动态代理常用的是JDK动态搭理或者字节码提升如CGLIB import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;/*** JDK动态代理实例*/ public class JDKDynamicProxyDemo {public static void main(String[] args) {ClassLoader classLoader Thread.currentThread().getContextClassLoader();// 真实的对象DefaultEchoService realObj new DefaultEchoService();// 代理的对象Object proxy Proxy.newProxyInstance(classLoader, new Class[]{EchoService.class}, new InvocationHandler() {Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println(动态前置);Object obj null;if (EchoService.class.isAssignableFrom(method.getDeclaringClass())) {// 执行真实方法obj method.invoke(realObj, args);}System.out.println(动态后置);return obj;}});EchoService echoService (EchoService) proxy;System.out.println(echoService.echo(Hello,World));} }注意这里需要DefaultEchoService 实现EchoService接口代理的其实是EchoService接口而不是DefaultEchoService 类。 动态代理对原代码没有侵入性通常可以动态加载。 2判断模式 类型Class、方法Method、注解Annotation、参数Parameter、异常Exception SpringAOP通常都是对方法的拦截此处的操作都是基于方法上的注解、参数、异常等。 public interface EchoService {String echo(String message) throws NullPointerException; }import org.springframework.util.ReflectionUtils; import java.lang.annotation.Annotation; import java.lang.reflect.Method;/*** AOP 目标过滤示例*/ public class TargetFilterDemo {public static void main(String[] args) throws ClassNotFoundException {String targetClassName com.demo.EchoService;// 获取当前线程 ClassLoaderClassLoader classLoader Thread.currentThread().getContextClassLoader();// 获取目标类Class? targetClass classLoader.loadClass(targetClassName);// 方法定义String echo(String message);// Spring 反射工具类获取目标类指定方法Method targetMethod ReflectionUtils.findMethod(targetClass, echo, String.class);System.out.println(targetMethod);// 查找方法 throws 类型为 NullPointerExceptionReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() {Overridepublic void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {System.out.println(仅抛出 NullPointerException 方法为 method);}}, new ReflectionUtils.MethodFilter() {// 对方法进行过滤Overridepublic boolean matches(Method method) {Class[] parameterTypes method.getParameterTypes(); // 判断参数Class[] exceptionTypes method.getExceptionTypes(); // 判断抛出的异常Annotation[] annotations method.getAnnotations(); // 判断注解return parameterTypes.length 1 String.class.equals(parameterTypes[0]) exceptionTypes.length 1 NullPointerException.class.equals(exceptionTypes[0]);}});} }3拦截模式 前置拦截Before、后置拦截After、异常拦截Exception、finally等等。 还有一种比较特殊的Around围绕模式。 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;/*** AOP拦截模式代码实例*/ public class InterceptorDemo {public static void main(String[] args) {ClassLoader classLoader Thread.currentThread().getContextClassLoader();// 真实的对象DefaultEchoService realObj new DefaultEchoService();// 前置拦截器Interceptor beforeInterceptor new Interceptor() {Overridepublic Object invoke(Object proxy, Method method, Object[] args, Object returnResult, Throwable throwable) {return System.currentTimeMillis();}};// 后置拦截器Interceptor afterInterceptor new Interceptor() {Overridepublic Object invoke(Object proxy, Method method, Object[] args, Object returnResult, Throwable throwable) {return System.currentTimeMillis();}};// 异常拦截器Interceptor exceptionInterceptor new Interceptor() {Overridepublic Object invoke(Object proxy, Method method, Object[] args, Object returnResult, Throwable throwable) {throwable.printStackTrace();return null;}};// finally拦截器Interceptor finallyInterceptor new Interceptor() {Overridepublic Object invoke(Object proxy, Method method, Object[] args, Object returnResult, Throwable throwable) {return null;}};// 代理的对象Object proxy Proxy.newProxyInstance(classLoader, new Class[]{EchoService.class}, new InvocationHandler() {Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Long startTime 0L;Long endTime 0L;Object result null;Object obj null;if (EchoService.class.isAssignableFrom(method.getDeclaringClass())) {try {// 执行beforestartTime (Long)beforeInterceptor.invoke(proxy, method, args, null, null);// 执行真实方法obj method.invoke(realObj, args);// 执行afterendTime (Long) afterInterceptor.invoke(proxy, method, args, obj, null);} catch (Exception e) {// 执行异常拦截器exceptionInterceptor.invoke(proxy, method, args, null, e);} finally {// 执行finallyfinallyInterceptor.invoke(proxy, method, args, obj, null);System.out.println(共消耗时间 (endTime - startTime));}}return obj;}});EchoService echoService (EchoService) proxy;System.out.println(echoService.echo(Hello,World));}static interface Interceptor {Object invoke(Object proxy, Method method, Object[] args, Object returnResult, Throwable throwable);} }Spring AOP也是基于类似的接口来进行实现的。 3、Spring AOP核心特性 • 纯 Java 实现、无编译时特殊处理、不修改和控制 ClassLoader • 仅支持方法级别的 Join Points • 非完整 AOP 实现框架 • 需要Spring IoC 容器整合 • AspectJ 注解驱动整合非竞争关系 Spring AOP(JDK动态代理CGLIB) 是运行期修改class文件AspectJ是编译期修改class文件。 Spring 并没有使用 AspectJ 的编译器而是利用反射来实现的后续慢慢讲解。 4、Spring AOP 编程模型 注解驱动 实现 Enable 模块驱动EnableAspectJAutoProxy 注解 • 激活 AspectJ 自动代理EnableAspectJAutoProxy • Aspect Aspect • Pointcut Pointcut • Advice Before、AfterReturning、AfterThrowing、After、Around • Introduction DeclareParents XML 配置驱动 实现 Spring Extensble XML Authoring XML 元素 • 激活 AspectJ 自动代理aop:aspectj-autoproxy/ • 配置aop:config/ • Aspect aop:aspect/ • Pointcut aop:pointcut/ • Advice aop:around/、aop:before/、aop:after-returning/、aop:after-throwing/ 和aop:after/ • Introduction aop:declare-parents/ • 代理 Scope aop:scoped-proxy/ 底层 API 实现 JDK 动态代理、CGLIB 以及 AspectJ API • 代理AopProxy • 配置ProxyConfig • Join PointJoinPoint • Pointcut Pointcut • Advice Advice、BeforeAdvice、AfterAdvice、AfterReturningAdvice、ThrowsAdvice 三、Spring AOP用到的代理方式 1、JDK 动态代理实现 JDK 动态代理实现一般是基于接口代理。在Spring中的核心类是JdkDynamicAopProxy它实现了AopProxy接口 public interface AopProxy {Object getProxy();Object getProxy(Nullable ClassLoader classLoader); }JDK动态代理的实例我们上面已经展示过了为什么 Proxy.newProxyInstance 会生成新的字节码 ClassLoader classLoader Thread.currentThread().getContextClassLoader();Object proxy Proxy.newProxyInstance(classLoader, new Class[]{EchoService.class}, new InvocationHandler() {Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {return null;} });System.out.println(proxy.getClass());// com.sun.proxy.$Proxy0Object proxy2 Proxy.newProxyInstance(classLoader, new Class[]{Comparable.class}, (proxy1, method, args1) - {return null;});System.out.println(proxy2.getClass());// com.sun.proxy.$Proxy1上面代码我们会发现Java动态代理每生成一个代理它的class总是com.sun.proxy包下的$Proxy*从0开始累加它是如何实现的呢 我们来分析一下Proxy的newProxyInstance方法 // java.lang.reflect.Proxy#newProxyInstance CallerSensitive public static Object newProxyInstance(ClassLoader loader,Class?[] interfaces,InvocationHandler h)throws IllegalArgumentException {Objects.requireNonNull(h);// 对象克隆final Class?[] intfs interfaces.clone();final SecurityManager sm System.getSecurityManager();if (sm ! null) {checkProxyAccess(Reflection.getCallerClass(), loader, intfs);}/** Look up or generate the designated proxy class.*/// 先从缓存获取见 1Class? cl getProxyClass0(loader, intfs);/** Invoke its constructor with the designated invocation handler.*/try {if (sm ! null) {checkNewProxyPermission(Reflection.getCallerClass(), cl);}// 获取代理对象的构造方法带着InvocationHandler参数的构造方法final Constructor? cons cl.getConstructor(constructorParams);final InvocationHandler ih h;if (!Modifier.isPublic(cl.getModifiers())) {AccessController.doPrivileged(new PrivilegedActionVoid() {public Void run() {cons.setAccessible(true);return null;}});}// 返回Proxy对象return cons.newInstance(new Object[]{h});} catch (IllegalAccessException|InstantiationException e) {throw new InternalError(e.toString(), e);} catch (InvocationTargetException e) {Throwable t e.getCause();if (t instanceof RuntimeException) {throw (RuntimeException) t;} else {throw new InternalError(t.toString(), t);}} catch (NoSuchMethodException e) {throw new InternalError(e.toString(), e);} }1getProxyClass0方法 在getProxyClass0方法中从proxyClassCache缓存中获取了这个代理类 // java.lang.reflect.Proxy#getProxyClass0 private static Class? getProxyClass0(ClassLoader loader,Class?... interfaces) {if (interfaces.length 65535) {throw new IllegalArgumentException(interface limit exceeded);}// If the proxy class defined by the given loader implementing// the given interfaces exists, this will simply return the cached copy;// otherwise, it will create the proxy class via the ProxyClassFactoryreturn proxyClassCache.get(loader, interfaces); }而proxyClassCache在初始化时自动创建了KeyFactory和ProxyClassFactory private static final WeakCacheClassLoader, Class?[], Class?proxyClassCache new WeakCache(new KeyFactory(), new ProxyClassFactory());ProxyClassFactory的核心方法apply隐藏着代理接口的创建逻辑 // java.lang.reflect.Proxy.ProxyClassFactory private static final class ProxyClassFactoryimplements BiFunctionClassLoader, Class?[], Class? {// prefix for all proxy class namesprivate static final String proxyClassNamePrefix $Proxy;// next number to use for generation of unique proxy class namesprivate static final AtomicLong nextUniqueNumber new AtomicLong();Overridepublic Class? apply(ClassLoader loader, Class?[] interfaces) {MapClass?, Boolean interfaceSet new IdentityHashMap(interfaces.length);for (Class? intf : interfaces) { // 遍历我们传入的接口数组/** Verify that the class loader resolves the name of this* interface to the same Class object.*/Class? interfaceClass null;try {// 通过classLoader加载我们的接口interfaceClass Class.forName(intf.getName(), false, loader);} catch (ClassNotFoundException e) {}if (interfaceClass ! intf) {throw new IllegalArgumentException(intf is not visible from class loader);}/** Verify that the Class object actually represents an* interface.*/if (!interfaceClass.isInterface()) {// 只能代理接口非接口直接抛异常throw new IllegalArgumentException(interfaceClass.getName() is not an interface);}/** Verify that this interface is not a duplicate.*/if (interfaceSet.put(interfaceClass, Boolean.TRUE) ! null) {throw new IllegalArgumentException(repeated interface: interfaceClass.getName());}}String proxyPkg null; // package to define proxy class inint accessFlags Modifier.PUBLIC | Modifier.FINAL;/** Record the package of a non-public proxy interface so that the* proxy class will be defined in the same package. Verify that* all non-public proxy interfaces are in the same package.*/for (Class? intf : interfaces) {int flags intf.getModifiers();if (!Modifier.isPublic(flags)) {accessFlags Modifier.FINAL;String name intf.getName();int n name.lastIndexOf(.);String pkg ((n -1) ? : name.substring(0, n 1));if (proxyPkg null) {proxyPkg pkg;} else if (!pkg.equals(proxyPkg)) {throw new IllegalArgumentException(non-public interfaces from different packages);}}}if (proxyPkg null) { // 包名就是com.sun.proxy// if no non-public proxy interfaces, use com.sun.proxy packageproxyPkg ReflectUtil.PROXY_PACKAGE .;}/** Choose a name for the proxy class to generate.*/long num nextUniqueNumber.getAndIncrement();String proxyName proxyPkg proxyClassNamePrefix num; // 依次递增/** Generate the specified proxy class.*/// 代理类生成器返回字节数组就是字节码byte[] proxyClassFile ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);try {// classLoader加载类是一个native方法返回一个Class对象return defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);} catch (ClassFormatError e) {/** A ClassFormatError here means that (barring bugs in the* proxy class generation code) there was some other* invalid aspect of the arguments supplied to the proxy* class creation (such as virtual machine limitations* exceeded).*/throw new IllegalArgumentException(e.toString());}} }3总结 vm options参数设置-Dsun.misc.ProxyGenerator.saveGeneratedFilestrue就可以把生成的代理类的源码保存在com.sun.proxy目录下面或者用arthas来查看运行中的类信息。 JDK动态代理生成的代理类我们通过反编译发现其实是这个样子的 package com.sun.proxy;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; import com.demo.EchoService;public final class $Proxy0 extends Proxy implements EchoService {private static Method m1;private static Method m3;private static Method m2;private static Method m0;public $Proxy0(InvocationHandler invocationHandler) {super(invocationHandler);}static {try {m1 Class.forName(java.lang.Object).getMethod(equals, Class.forName(java.lang.Object));m3 Class.forName(com.demo.EchoService).getMethod(echo, Class.forName(java.lang.String));m2 Class.forName(java.lang.Object).getMethod(toString, new Class[0]);m0 Class.forName(java.lang.Object).getMethod(hashCode, new Class[0]);return;}catch (NoSuchMethodException noSuchMethodException) {throw new NoSuchMethodError(noSuchMethodException.getMessage());}catch (ClassNotFoundException classNotFoundException) {throw new NoClassDefFoundError(classNotFoundException.getMessage());}}public final boolean equals(Object object) {try {return (Boolean)this.h.invoke(this, m1, new Object[]{object});}catch (Error | RuntimeException throwable) {throw throwable;}catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}public final String toString() {try {return (String)this.h.invoke(this, m2, null);}catch (Error | RuntimeException throwable) {throw throwable;}catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}public final int hashCode() {try {return (Integer)this.h.invoke(this, m0, null);}catch (Error | RuntimeException throwable) {throw throwable;}catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}public final String echo(String string) throws NullPointerException {try {return (String)this.h.invoke(this, m3, new Object[]{string});}catch (Error | RuntimeException throwable) {throw throwable;}catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}} }InvocationHandler就是Proxy.newProxyInstance传入的最后一个参数。 当调用代理对象的方法时会执行InvocationHandler的invoke方法。 注意JDK生成的代理类的包名不总是com.sun.proxy,只有当接口为Public时是这样的当接口为非public时生成的代理类与接口所在包名相同。 2、CGLIB 动态代理实现Spring中 CGLIB 动态代理实现一般是基于类代理字节码提升。在Spring中核心类是CglibAopProxy同样实现了AopProxy接口。 1代码实例 import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** CGLIB 动态代理示例*/ public class CglibDynamicProxyDemo {public static void main(String[] args) {Enhancer enhancer new Enhancer();// 指定 super class DefaultEchoService.classClass? superClass DefaultEchoService.class;enhancer.setSuperclass(superClass);// 指定拦截接口可以不写//enhancer.setInterfaces(new Class[]{EchoService.class});enhancer.setCallback(new MethodInterceptor() {Overridepublic Object intercept(Object source, Method method, Object[] args,MethodProxy methodProxy) throws Throwable {long startTime System.currentTimeMillis();// 错误使用 // Object result method.invoke(source, args);// 正确的方法调用Object result methodProxy.invokeSuper(source, args);long costTime System.currentTimeMillis() - startTime;System.out.println([CGLIB 字节码提升] echo 方法执行的实现 costTime ms.);return result;}});// 创建代理对象EchoService echoService (EchoService) enhancer.create();// 输出执行结果System.out.println(echoService.echo(Hello,World)); // 8ms对性能影响较大} } 2总结 Java 动态代理无法满足 AOP 的需要JDK动态代理只能针对interface进行动态代理无法对普通类进行动态代理Java动态代理使用Java原生的反射API进行操作在生成类上比较高效。 CGLIB能够代理普通类可以不需要接口 CGLIB使用ASM框架直接对字节码进行操作在类的执行过程中比较高效但是类的创建过程比较耗时。 CGLIB默认是在类同包下生成一个类通过反编译我们发现生成的代理类如下 import java.lang.reflect.Method; import com.demo.DefaultEchoService; import org.springframework.cglib.core.ReflectUtils; import org.springframework.cglib.core.Signature; import org.springframework.cglib.proxy.Callback; import org.springframework.cglib.proxy.Factory; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy;public class DefaultEchoService$$EnhancerByCGLIB$$c868af31 extends DefaultEchoService implements Factory {private boolean CGLIB$BOUND;public static Object CGLIB$FACTORY_DATA;private static final ThreadLocal CGLIB$THREAD_CALLBACKS;private static final Callback[] CGLIB$STATIC_CALLBACKS;private MethodInterceptor CGLIB$CALLBACK_0;private static Object CGLIB$CALLBACK_FILTER;private static final Method CGLIB$echo$0$Method;private static final MethodProxy CGLIB$echo$0$Proxy;private static final Object[] CGLIB$emptyArgs;private static final Method CGLIB$equals$1$Method;private static final MethodProxy CGLIB$equals$1$Proxy;private static final Method CGLIB$toString$2$Method;private static final MethodProxy CGLIB$toString$2$Proxy;private static final Method CGLIB$hashCode$3$Method;private static final MethodProxy CGLIB$hashCode$3$Proxy;private static final Method CGLIB$clone$4$Method;private static final MethodProxy CGLIB$clone$4$Proxy;static void CGLIB$STATICHOOK1() {CGLIB$THREAD_CALLBACKS new ThreadLocal();CGLIB$emptyArgs new Object[0];Class? clazz Class.forName(com.demo.DefaultEchoService$$EnhancerByCGLIB$$c868af31);Class? clazz2 Class.forName(com.demo.DefaultEchoService);CGLIB$echo$0$Method ReflectUtils.findMethods(new String[]{echo, (Ljava/lang/String;)Ljava/lang/String;}, clazz2.getDeclaredMethods())[0];CGLIB$echo$0$Proxy MethodProxy.create(clazz2, clazz, (Ljava/lang/String;)Ljava/lang/String;, echo, CGLIB$echo$0);clazz2 Class.forName(java.lang.Object);Method[] methodArray ReflectUtils.findMethods(new String[]{equals, (Ljava/lang/Object;)Z, toString, ()Ljava/lang/String;, hashCode, ()I, clone, ()Ljava/lang/Object;}, clazz2.getDeclaredMethods());CGLIB$equals$1$Method methodArray[0];CGLIB$equals$1$Proxy MethodProxy.create(clazz2, clazz, (Ljava/lang/Object;)Z, equals, CGLIB$equals$1);CGLIB$toString$2$Method methodArray[1];CGLIB$toString$2$Proxy MethodProxy.create(clazz2, clazz, ()Ljava/lang/String;, toString, CGLIB$toString$2);CGLIB$hashCode$3$Method methodArray[2];CGLIB$hashCode$3$Proxy MethodProxy.create(clazz2, clazz, ()I, hashCode, CGLIB$hashCode$3);CGLIB$clone$4$Method methodArray[3];CGLIB$clone$4$Proxy MethodProxy.create(clazz2, clazz, ()Ljava/lang/Object;, clone, CGLIB$clone$4);}final String CGLIB$echo$0(String string) {return super.echo(string);}public final String echo(String string) {MethodInterceptor methodInterceptor this.CGLIB$CALLBACK_0;if (methodInterceptor null) {DefaultEchoService$$EnhancerByCGLIB$$c868af31.CGLIB$BIND_CALLBACKS(this);methodInterceptor this.CGLIB$CALLBACK_0;}if (methodInterceptor ! null) {return (String)methodInterceptor.intercept(this, CGLIB$echo$0$Method, new Object[]{string}, CGLIB$echo$0$Proxy);}return super.echo(string);}final boolean CGLIB$equals$1(Object object) {return super.equals(object);}public final boolean equals(Object object) {MethodInterceptor methodInterceptor this.CGLIB$CALLBACK_0;if (methodInterceptor null) {DefaultEchoService$$EnhancerByCGLIB$$c868af31.CGLIB$BIND_CALLBACKS(this);methodInterceptor this.CGLIB$CALLBACK_0;}if (methodInterceptor ! null) {Object object2 methodInterceptor.intercept(this, CGLIB$equals$1$Method, new Object[]{object}, CGLIB$equals$1$Proxy);return object2 null ? false : (Boolean)object2;}return super.equals(object);}final String CGLIB$toString$2() {return super.toString();}public final String toString() {MethodInterceptor methodInterceptor this.CGLIB$CALLBACK_0;if (methodInterceptor null) {DefaultEchoService$$EnhancerByCGLIB$$c868af31.CGLIB$BIND_CALLBACKS(this);methodInterceptor this.CGLIB$CALLBACK_0;}if (methodInterceptor ! null) {return (String)methodInterceptor.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy);}return super.toString();}final int CGLIB$hashCode$3() {return super.hashCode();}public final int hashCode() {MethodInterceptor methodInterceptor this.CGLIB$CALLBACK_0;if (methodInterceptor null) {DefaultEchoService$$EnhancerByCGLIB$$c868af31.CGLIB$BIND_CALLBACKS(this);methodInterceptor this.CGLIB$CALLBACK_0;}if (methodInterceptor ! null) {Object object methodInterceptor.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);return object null ? 0 : ((Number)object).intValue();}return super.hashCode();}final Object CGLIB$clone$4() throws CloneNotSupportedException {return super.clone();}protected final Object clone() throws CloneNotSupportedException {MethodInterceptor methodInterceptor this.CGLIB$CALLBACK_0;if (methodInterceptor null) {DefaultEchoService$$EnhancerByCGLIB$$c868af31.CGLIB$BIND_CALLBACKS(this);methodInterceptor this.CGLIB$CALLBACK_0;}if (methodInterceptor ! null) {return methodInterceptor.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy);}return super.clone();}public static MethodProxy CGLIB$findMethodProxy(Signature signature) {String string ((Object)signature).toString();switch (string.hashCode()) {case -1042135322: {if (!string.equals(echo(Ljava/lang/String;)Ljava/lang/String;)) break;return CGLIB$echo$0$Proxy;}case -508378822: {if (!string.equals(clone()Ljava/lang/Object;)) break;return CGLIB$clone$4$Proxy;}case 1826985398: {if (!string.equals(equals(Ljava/lang/Object;)Z)) break;return CGLIB$equals$1$Proxy;}case 1913648695: {if (!string.equals(toString()Ljava/lang/String;)) break;return CGLIB$toString$2$Proxy;}case 1984935277: {if (!string.equals(hashCode()I)) break;return CGLIB$hashCode$3$Proxy;}}return null;}public DefaultEchoService$$EnhancerByCGLIB$$c868af31() {DefaultEchoService$$EnhancerByCGLIB$$c868af31 defaultEchoService$$EnhancerByCGLIB$$c868af31 this;DefaultEchoService$$EnhancerByCGLIB$$c868af31.CGLIB$BIND_CALLBACKS(defaultEchoService$$EnhancerByCGLIB$$c868af31);}public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] callbackArray) {CGLIB$THREAD_CALLBACKS.set(callbackArray);}public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] callbackArray) {CGLIB$STATIC_CALLBACKS callbackArray;}private static final void CGLIB$BIND_CALLBACKS(Object object) {block2: {Object object2;block3: {DefaultEchoService$$EnhancerByCGLIB$$c868af31 defaultEchoService$$EnhancerByCGLIB$$c868af31 (DefaultEchoService$$EnhancerByCGLIB$$c868af31)object;if (defaultEchoService$$EnhancerByCGLIB$$c868af31.CGLIB$BOUND) break block2;defaultEchoService$$EnhancerByCGLIB$$c868af31.CGLIB$BOUND true;object2 CGLIB$THREAD_CALLBACKS.get();if (object2 ! null) break block3;object2 CGLIB$STATIC_CALLBACKS;if (CGLIB$STATIC_CALLBACKS null) break block2;}defaultEchoService$$EnhancerByCGLIB$$c868af31.CGLIB$CALLBACK_0 (MethodInterceptor)((Callback[])object2)[0];}}Overridepublic Object newInstance(Callback[] callbackArray) {DefaultEchoService$$EnhancerByCGLIB$$c868af31.CGLIB$SET_THREAD_CALLBACKS(callbackArray);DefaultEchoService$$EnhancerByCGLIB$$c868af31 defaultEchoService$$EnhancerByCGLIB$$c868af31 new DefaultEchoService$$EnhancerByCGLIB$$c868af31();DefaultEchoService$$EnhancerByCGLIB$$c868af31.CGLIB$SET_THREAD_CALLBACKS(null);return defaultEchoService$$EnhancerByCGLIB$$c868af31;}Overridepublic Object newInstance(Callback callback) {DefaultEchoService$$EnhancerByCGLIB$$c868af31.CGLIB$SET_THREAD_CALLBACKS(new Callback[]{callback});DefaultEchoService$$EnhancerByCGLIB$$c868af31 defaultEchoService$$EnhancerByCGLIB$$c868af31 new DefaultEchoService$$EnhancerByCGLIB$$c868af31();DefaultEchoService$$EnhancerByCGLIB$$c868af31.CGLIB$SET_THREAD_CALLBACKS(null);return defaultEchoService$$EnhancerByCGLIB$$c868af31;}Overridepublic Object newInstance(Class[] classArray, Object[] objectArray, Callback[] callbackArray) {DefaultEchoService$$EnhancerByCGLIB$$c868af31 defaultEchoService$$EnhancerByCGLIB$$c868af31;DefaultEchoService$$EnhancerByCGLIB$$c868af31.CGLIB$SET_THREAD_CALLBACKS(callbackArray);Class[] classArray2 classArray;switch (classArray.length) {case 0: {defaultEchoService$$EnhancerByCGLIB$$c868af31 new DefaultEchoService$$EnhancerByCGLIB$$c868af31();break;}default: {throw new IllegalArgumentException(Constructor not found);}}DefaultEchoService$$EnhancerByCGLIB$$c868af31.CGLIB$SET_THREAD_CALLBACKS(null);return defaultEchoService$$EnhancerByCGLIB$$c868af31;}Overridepublic Callback getCallback(int n) {MethodInterceptor methodInterceptor;DefaultEchoService$$EnhancerByCGLIB$$c868af31.CGLIB$BIND_CALLBACKS(this);switch (n) {case 0: {methodInterceptor this.CGLIB$CALLBACK_0;break;}default: {methodInterceptor null;}}return methodInterceptor;}Overridepublic void setCallback(int n, Callback callback) {switch (n) {case 0: {this.CGLIB$CALLBACK_0 (MethodInterceptor)callback;break;}}}Overridepublic Callback[] getCallbacks() {DefaultEchoService$$EnhancerByCGLIB$$c868af31.CGLIB$BIND_CALLBACKS(this);DefaultEchoService$$EnhancerByCGLIB$$c868af31 defaultEchoService$$EnhancerByCGLIB$$c868af31 this;return new Callback[]{this.CGLIB$CALLBACK_0};}Overridepublic void setCallbacks(Callback[] callbackArray) {Callback[] callbackArray2 callbackArray;DefaultEchoService$$EnhancerByCGLIB$$c868af31 defaultEchoService$$EnhancerByCGLIB$$c868af31 this;this.CGLIB$CALLBACK_0 (MethodInterceptor)callbackArray[0];}static {DefaultEchoService$$EnhancerByCGLIB$$c868af31.CGLIB$STATICHOOK1();} }我们可以看出生成这个类比JDK动态代理生成的类复杂多了但是也不难看出该代理类继承了我们的父类DefaultEchoService并不像JDK动态代理那样必须实现同一个接口。 而且代理类的echo方法是直接调用的super.echo()方法不像JDK动态代理使用的是反射调用的所以CGLIB执行的性能是略优于JDK动态代理的但是代理类的生成速度是比较差的。 3、AspectJ 适配实现 AspectJ动态代理实现核心类是AspectJProxyFactory与AspectJ实现了整合。 Spring aop包含 jdk动态代理、cglib动态代理和aspectj而DefaultAopProxyFactory 却只包含了前两种创建代理对象的实现而没包含aspectj而是单独定义了一个AspectJProxyFactory。实际上 Spring AOP 整合 AspectJ 时并未使用 AspectJ 的编译器它是基于 Java 反射来实现所以只有两种创建代理的方式。这个问题后续会慢慢讲明白。 Spring官网 推荐使用 AspectJ 注解。AspectJ是一种将方面声明为带有注释的常规Java类的风格。AspectJ样式是由AspectJ项目作为AspectJ 5发行版的一部分引入的。Spring解释与AspectJ 5相同的注释使用AspectJ提供的切入点解析和匹配库。不过AOP运行时仍然是纯Spring AOP并且不依赖于AspectJ编译器或waever提升器。 1AspectJ 语法 • Aspect • Join Points • Pointcuts • Advice • Introduction aspectj官方文档 AspectJ 语法用起来对程序员非常不友好Spring中建议使用AspectJ的注解方式Spring将其与IOC完美结合了。 2AspectJ 注解 • 激活 AspectJ 自动代理EnableAspectJAutoProxy • Aspect Aspect • Pointcut Pointcut • Advice Before、AfterReturning、AfterThrowing、After、Around • Introduction DeclareParents 3总结 代理的类型只有两种 JDK 动态代理和 CGLIB 代理AspectJAopProxy 只是一种利用 AspectJ 表达式的提升简化了繁杂的 Spring AOP API 的实现。 Spring AOP代理对象还是由JDK动态代理或者是Cglib来实现。AspectJ 主要被 Spring 用于解析其 Pointcut 表达式 4Spring AOP 和 AspectJ AOP 存在哪些区别 • AspectJ 是 _x0008_AOP 完整实现Spring AOP 则是部分实现 • Spring AOP 比 AspectJ 使用更简单 • Spring AOP 整合 AspectJ 注解与 Spring IoC 容器 • Spring AOP 仅支持基于代理模式的 AOP • Spring AOP 仅支持方法级别的 Pointcuts 未完待续 参考资料 极客时间《小马哥讲 Spring AOP 编程思想》
http://www.dnsts.com.cn/news/227599.html

相关文章:

  • iis搭建网站时宁波英文网站建设
  • 网站开发系统论文域名被墙查询检测
  • 网盘做网站空间企业名词解释
  • 网站建设 军报wordpress前端页面模板
  • 58招聘网站官网想学做宝宝食谱上什么网站
  • 网站启用cdn加速网站建设的工具是
  • app推广一手单吉安做网站优化
  • flash网站标题和网址网站页面图片布局如何设计
  • 自己建设个小网站要什么手续好网站的标准
  • 自助式网站制作织梦校园招生网站源码
  • 精品课程网站建设方案成都著名设计师
  • 西安有关做网站的公司html5基础知识
  • 网站建设报价单模板wordpress技术站主题
  • 无锡手机网站制作界面设计是什么
  • 做壁纸的专业网站永州市建设工程质量安全监督站官方网站
  • 张家港建网站的公司网站建设题库
  • 商城网站页面设计有了网站怎么写文章
  • 开展建设文明网站活动交通门户网站建设
  • 邢台做网站改版网站的优化承诺
  • 站长之家网页模板下载什么网站可以自己接工程做预算
  • 信阳网站建设哪家好广州力科网站建设公司
  • 小说网站怎么做权重杨凌规划建设局网站
  • vs2017网站开发中国光大国际建设工程公司网站
  • 外贸网站建设谷歌推广下面哪些不是网页制作工具
  • 用jsp源码做网站自己建网站要多少钱
  • 如何通过网站后台修改网站上海做得好的网站建设公司
  • 深圳企业网站制作设计方案昆明网站建设是什么意思
  • 什么是网站栏目标题制作网页app
  • 公共网站怎地做网站图片怎么做缓存
  • 淘宝网站建设类别长春净月潭建设投资集团网站