Spring温故而知新系列教程之AOP代理

AOP的概念

AOP:Aspect-Oriented Programming(面向切面编程),维基百科的解释如下:Aspect是一种新的模块化机制,用来描述分散在对象、类或者函数中的横切关注点,从关注点中分离出横切关注点是面向切面的程序设计的核心概念。分离关注点使解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑的代码中不在含有针对特定领域问题的代码的调用,业务逻辑同特定领域问题的关系通过切面来封装、维护,这样原本分散在整个应用程序中的变动就可以很好地管理起来。从AOP的角度,应用可以分为横切关注点和业务逻辑代码,实际开发中,这些横切关注点往往会直接嵌入到业务逻辑代码中,面向切面编程就是要解决把横切关注点与业务逻辑相分离

实现方式:

Spring默认使用 JDK 动态代理作为AOP的代理,缺陷是目标类的类必须实现接口,否则不能使用JDK动态代理。如果需要代理的是类而不是接口,那么Spring会默认使用CGLIB代理,关于两者的区别:jdk动态代理是通过java的反射机制来实现的,目标类必须要实现接口,cglib是针对类来实现代理的,他的原理是动态的为指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

JDK动态代理

Jdk动态代理是在程序运行过程中,根据目标类实现的接口来动态生成代理类的class文件,使用主要涉及两个类:

InvocationHandler接口: 它提供了一个invoke(Object obj,Method method, Object[] args)方法供实现者提供相应的代理逻辑的实现。可以对实际的实现进行一些特殊的处理其中参数

            Object obj :被代理的目标类

            Method method: 需要执行的目标类的方法

            Object[] args :目标方法的参数

Proxy类:提供一个方法newProxyInstance (ClassLoader loader, Class[] interfaces, InvocationHandler h)来获得动态代理类

示例代码:

public interface OrderService {
 public void createOrder();
}
public class OrderServiceImpl implements OrderService {

 @Override
 public void createOrder() {
 System.out.println("creating order");
 }
}
public class OrderLogger {
 public void beforeCreateOrder(){
 System.out.println("before create order");
 }

 public void afterCreateOrder(){
 System.out.println("after create order");
 }
}
package com.sl.aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ServiceProxy implements InvocationHandler {
 private Object targetClass;
 private OrderLogger orderLogger;
 public ServiceProxy(Object targetClass,OrderLogger orderLogger) {
 this.targetClass = targetClass;
 this.orderLogger = orderLogger;
 }

 //获取代理
 public Object GetDynamicProxy()
 {
 return Proxy.newProxyInstance(targetClass.getClass().getClassLoader(), //通过这个ClassLoader生成代理对象
 targetClass.getClass().getInterfaces(),//代理类已实现的接口
 this); //动态代理调用方法是关联的InvocationHandler,最终通过此InvocationHandler的invoke方法执行真正的方法
 }

 //实现相应的代理逻辑
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 this.orderLogger.beforeCreateOrder();
 Object result= method.invoke(targetClass, args);
 this.orderLogger.afterCreateOrder();
 return result;
 }
}

测试类:

package com.sl.aop;
import org.junit.Test;
public class AopTest {
 @Test
 public void Testdynamicproxy() {

 OrderServiceImpl serviceImpl = new OrderServiceImpl();
 OrderLogger logger = new OrderLogger();
 OrderService service = (OrderService) new ServiceProxy(serviceImpl, logger).GetDynamicProxy();
 service.createOrder();
 }
}

运行结果:

到这个其实还是有点困惑,Proxy.newProxyInstance()这个返回的是什么? Invoke方法在哪里调用的?我们看一下JDK源码:看看DK动态代理的过程是什么样的:

根据源码内部的函数调用Proxy.newProxyInstance()->Proxy.getProxyClass0()->WeakCache.get() ,先定位到

WeakCache.class:

public V get(K key, P parameter) {
 Objects.requireNonNull(parameter);

 expungeStaleEntries();

 Object cacheKey = CacheKey.valueOf(key, refQueue);

 // lazily install the 2nd level valuesMap for the particular cacheKey
 ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
 if (valuesMap == null) {
 ConcurrentMap<Object, Supplier<V>> oldValuesMap
 = map.putIfAbsent(cacheKey,
   valuesMap = new ConcurrentHashMap<>());
 if (oldValuesMap != null) {
 valuesMap = oldValuesMap;
 }
 }

 // create subKey and retrieve the possible Supplier<V> stored by that
 // subKey from valuesMap
 Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
 Supplier<V> supplier = valuesMap.get(subKey);
 Factory factory = null;

 while (true) {
 if (supplier != null) {
 // supplier might be a Factory or a CacheValue<V> instance
 V value = supplier.get();
 if (value != null) {
  return value;
 }
 }
 // else no supplier in cache
 // or a supplier that returned null (could be a cleared CacheValue
 // or a Factory that wasn't successful in installing the CacheValue)

 // lazily construct a Factory
 if (factory == null) {
 factory = new Factory(key, parameter, subKey, valuesMap);
 }

 if (supplier == null) {
 supplier = valuesMap.putIfAbsent(subKey, factory);
 if (supplier == null) {
  // successfully installed Factory
  supplier = factory;
 }
 // else retry with winning supplier
 } else {
 if (valuesMap.replace(subKey, supplier, factory)) {
  // successfully replaced
  // cleared CacheEntry / unsuccessful Factory
  // with our Factory
  supplier = factory;
 } else {
  // retry with current supplier
  supplier = valuesMap.get(subKey);
 }
 }
 }
 }

可以看到函数return value;  而 V value = supplier.get();   继续往下读可以发现 supper=factory,实际上是一个Factory对象,那么继续查看Factory.get()方法

public synchronized V get() { // serialize access
 // re-check
 Supplier<V> supplier = valuesMap.get(subKey);
 if (supplier != this) {
 // something changed while we were waiting:
 // might be that we were replaced by a CacheValue
 // or were removed because of failure ->
 // return null to signal WeakCache.get() to retry
 // the loop
 return null;
 }
 // else still us (supplier == this)

 // create new value
 V value = null;
 try {
 value = Objects.requireNonNull(valueFactory.apply(key, parameter));
 } finally {
 if (value == null) { // remove us on failure
  valuesMap.remove(subKey, this);
 }
 }
 // the only path to reach here is with non-null value
 assert value != null;

 // wrap value with CacheValue (WeakReference)
 CacheValue<V> cacheValue = new CacheValue<>(value);

 // try replacing us with CacheValue (this should always succeed)
 if (valuesMap.replace(subKey, this, cacheValue)) {
 // put also in reverseMap
 reverseMap.put(cacheValue, Boolean.TRUE);
 } else {
 throw new AssertionError("Should not reach here");
 }

 // successfully replaced us with new CacheValue -> return the value
 // wrapped by it
 return value;
 }

Return value;那么直接查看赋值语句:value = Objects.requireNonNull(valueFactory.apply(key, parameter));

valueFactory又什么鬼?

public WeakCache(BiFunction<K, P, ?> subKeyFactory,
  BiFunction<K, P, V> valueFactory) {
 this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
 this.valueFactory = Objects.requireNonNull(valueFactory);
 }

private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

可以知道valueFactory是ProxyClassFactory类型对象,直接查看ProxyClassFactory. Apply()方法

public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

 Map<Class<?>, 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 {
  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 in
 int 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) {
 // if no non-public proxy interfaces, use com.sun.proxy package
 proxyPkg = 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 {
 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());
 }
 }
}

直接画重点:

byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
 proxyName, interfaces, accessFlags);
return defineClass0(loader, proxyName,
   proxyClassFile, 0, proxyClassFile.length);

调用ProxyGenerator.generateProxyClass最终动态生成一个代理类,但是似乎并未找到何处调用了invoke方法;参考CSDN: //www.jb51.net/article/118935.htm这篇文章,尝试将这个动态生成的二进制字节码输出到本地,并反编译出来一看究竟,测试代码如下:

public class AopTest {
 @Test
 public void Testdynamicproxy() {

 OrderServiceImpl serviceImpl = new OrderServiceImpl();
 OrderLogger logger = new OrderLogger();
 OrderService service = (OrderService) new ServiceProxy(serviceImpl, logger).GetDynamicProxy();
 service.createOrder();
 //输出动态代理类字节码
 createProxyClassFile();
 }

 private static void createProxyClassFile(){
 String name = "ProxyObject";
 byte[] data = ProxyGenerator.generateProxyClass(name,new Class[]{OrderService.class});
 FileOutputStream out =null;
 try {
 out = new FileOutputStream(name+".class");
 System.out.println((new File("hello")).getAbsolutePath());
 out.write(data);
 } catch (FileNotFoundException e) {
 e.printStackTrace();
 } catch (IOException e) {
 e.printStackTrace();
 }finally {
 if(null!=out) try {
 out.close();
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
 }
}

使用java Decompiler工具将这个二进制class文件反编译查看:

具体动态代理类ProxyObject.java:

import com.sl.aop.OrderService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class ProxyObject
 extends Proxy
 implements OrderService
{
 private static Method m1;
 private static Method m2;
 private static Method m3;
 private static Method m0;

 public ProxyObject(InvocationHandler paramInvocationHandler)
 {
 super(paramInvocationHandler);
 }

 public final boolean equals(Object paramObject)
 {
 try
 {
 return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
 }
 catch (Error|RuntimeException localError)
 {
 throw localError;
 }
 catch (Throwable localThrowable)
 {
 throw new UndeclaredThrowableException(localThrowable);
 }
 }

 public final String toString()
 {
 try
 {
 return (String)this.h.invoke(this, m2, null);
 }
 catch (Error|RuntimeException localError)
 {
 throw localError;
 }
 catch (Throwable localThrowable)
 {
 throw new UndeclaredThrowableException(localThrowable);
 }
 }

 public final void createOrder()
 {
 try
 {
 this.h.invoke(this, m3, null);
 return;
 }
 catch (Error|RuntimeException localError)
 {
 throw localError;
 }
 catch (Throwable localThrowable)
 {
 throw new UndeclaredThrowableException(localThrowable);
 }
 }

 public final int hashCode()
 {
 try
 {
 return ((Integer)this.h.invoke(this, m0, null)).intValue();
 }
 catch (Error|RuntimeException localError)
 {
 throw localError;
 }
 catch (Throwable localThrowable)
 {
 throw new UndeclaredThrowableException(localThrowable);
 }
 }

 static
 {
 try
 {
 m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
 m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
 m3 = Class.forName("com.sl.aop.OrderService").getMethod("createOrder", new Class[0]);
 m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
 return;
 }
 catch (NoSuchMethodException localNoSuchMethodException)
 {
 throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
 }
 catch (ClassNotFoundException localClassNotFoundException)
 {
 throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
 }
 }

终于看到关于invoke的部分了:

public final void createOrder()
 {
 try
 {
 this.h.invoke(this, m3, null);
 return;
 }
 catch (Error|RuntimeException localError)
 {
 throw localError;
 }
 catch (Throwable localThrowable)
 {
 throw new UndeclaredThrowableException(localThrowable);
 }
 }

实际上动态代理类继承自Proxy,并且实现了目标类继承的接口,在createOrder方法中调用了invoke方法,实现了切面逻辑的植入,这里也回答了一个问题,为什么JDK动态代理的目标类必须是实现接口的,因为代理类其实是针对接口代理,而不是针对类来代理的,动态代理类自己继承自Proxy,Java也不允许多重继承。动态代理类和目标类其实是各自实现了接口,代理类通过InvocationHandler.invoke实现对目标类方法的调用。

CGLIB动态代理

CGLIB代理是通过使用一个字节码处理框架ASM,来转换字节码并生成新的类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,实现织如如横切逻辑 ,效率上比使用反射技术的JDK动态代理要高,但是由于CGLIB的原理是动态为目标类生成子类代理类,所以不能为声明为final的方法进行代理。其使用主要涉及两个类:

MethodInterceptor接口:该接口提供一个方法intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3)主要用于拦截目标类方法的调用

        Object arg0, :被代理的目标类

          Method arg1, 委托方法

        Object[] arg2, 方法参数

        MethodProxy arg3 :代理方法的MethodProxy对象

Enhancer类:用于创建代理类

示例:

实现MethodInterceptor接口,代理类在调用方法时,CGLIB会回调MethodInterceptor接口intercept方法,从而织入切面逻辑。

package com.sl.aop;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class CglibServiceProxy implements MethodInterceptor {

 private Object targetClass;
 private OrderLogger orderLogger;

 public CglibServiceProxy(Object targetClass,OrderLogger orderLogger) {
 this.targetClass = targetClass;
 this.orderLogger = orderLogger;
 }
 /**
 * 创建代理对象
 *
 */
 public Object getInstance() {
 Enhancer enhancer = new Enhancer(); 

 //设置目标类(需要被代理的类)
 enhancer.setSuperclass(this.targetClass.getClass());

 // 回调方法
 enhancer.setCallback(this);

 // 创建代理对象
 return enhancer.create();
 } 

 /**
 * 拦截所有目标类方法的调用
 *
 */
 @Override
 public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
 orderLogger.beforeCreateOrder(); 

 Object o1 = arg3.invokeSuper(arg0, arg2);

 orderLogger.afterCreateOrder();
 return o1;
 }
}

测试方法:

public void Testdynamicproxy() {
 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class");
 OrderServiceImpl serviceImpl = new OrderServiceImpl();
 OrderLogger logger = new OrderLogger();
 CglibServiceProxy proxy = new CglibServiceProxy(serviceImpl,logger);
  //通过生成子类的方式创建代理类
 OrderServiceImpl proxyImp = (OrderServiceImpl)proxy.getInstance();
 proxyImp.createOrder();
 }

结果:

System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class");将cglib动态代理类输出到指定目录,反编译查看一下代理类真面目:

package com.sl.aop;
import com.sl.aop.OrderServiceImpl;
import java.lang.reflect.Method;
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 OrderServiceImpl$$EnhancerByCGLIB$$17779aa4 extends OrderServiceImpl 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$createOrder$0$Method;
 private static final MethodProxy CGLIB$createOrder$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 var0 = Class.forName("com.sl.aop.OrderServiceImpl$$EnhancerByCGLIB$$17779aa4");
 Class var1;
 Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
 CGLIB$equals$1$Method = var10000[0];
 CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
 CGLIB$toString$2$Method = var10000[1];
 CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
 CGLIB$hashCode$3$Method = var10000[2];
 CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
 CGLIB$clone$4$Method = var10000[3];
 CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
 CGLIB$createOrder$0$Method = ReflectUtils.findMethods(new String[]{"createOrder", "()V"}, (var1 = Class.forName("com.sl.aop.OrderServiceImpl")).getDeclaredMethods())[0];
 CGLIB$createOrder$0$Proxy = MethodProxy.create(var1, var0, "()V", "createOrder", "CGLIB$createOrder$0");
 }

 final void CGLIB$createOrder$0() {
 super.createOrder();
 }

 public final void createOrder() {
 MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
 if(this.CGLIB$CALLBACK_0 == null) {
  CGLIB$BIND_CALLBACKS(this);
  var10000 = this.CGLIB$CALLBACK_0;
 }

 if(var10000 != null) {
  var10000.intercept(this, CGLIB$createOrder$0$Method, CGLIB$emptyArgs, CGLIB$createOrder$0$Proxy);
 } else {
  super.createOrder();
 }
 }

 final boolean CGLIB$equals$1(Object var1) {
 return super.equals(var1);
 }

 public final boolean equals(Object var1) {
 MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
 if(this.CGLIB$CALLBACK_0 == null) {
  CGLIB$BIND_CALLBACKS(this);
  var10000 = this.CGLIB$CALLBACK_0;
 }

 if(var10000 != null) {
  Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
  return var2 == null?false:((Boolean)var2).booleanValue();
 } else {
  return super.equals(var1);
 }
 }

 final String CGLIB$toString$2() {
 return super.toString();
 }

 public final String toString() {
 MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
 if(this.CGLIB$CALLBACK_0 == null) {
  CGLIB$BIND_CALLBACKS(this);
  var10000 = this.CGLIB$CALLBACK_0;
 }

 return var10000 != null?(String)var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy):super.toString();
 }

 final int CGLIB$hashCode$3() {
 return super.hashCode();
 }

 public final int hashCode() {
 MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
 if(this.CGLIB$CALLBACK_0 == null) {
  CGLIB$BIND_CALLBACKS(this);
  var10000 = this.CGLIB$CALLBACK_0;
 }

 if(var10000 != null) {
  Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
  return var1 == null?0:((Number)var1).intValue();
 } else {
  return super.hashCode();
 }
 }

 final Object CGLIB$clone$4() throws CloneNotSupportedException {
 return super.clone();
 }

 protected final Object clone() throws CloneNotSupportedException {
 MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
 if(this.CGLIB$CALLBACK_0 == null) {
  CGLIB$BIND_CALLBACKS(this);
  var10000 = this.CGLIB$CALLBACK_0;
 }

 return var10000 != null?var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy):super.clone();
 }

 public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
 String var10000 = var0.toString();
 switch(var10000.hashCode()) {
 case -2138148221:
  if(var10000.equals("createOrder()V")) {
  return CGLIB$createOrder$0$Proxy;
  }
  break;
 case -508378822:
  if(var10000.equals("clone()Ljava/lang/Object;")) {
  return CGLIB$clone$4$Proxy;
  }
  break;
 case 1826985398:
  if(var10000.equals("equals(Ljava/lang/Object;)Z")) {
  return CGLIB$equals$1$Proxy;
  }
  break;
 case 1913648695:
  if(var10000.equals("toString()Ljava/lang/String;")) {
  return CGLIB$toString$2$Proxy;
  }
  break;
 case 1984935277:
  if(var10000.equals("hashCode()I")) {
  return CGLIB$hashCode$3$Proxy;
  }
 }

 return null;
 }

 public OrderServiceImpl$$EnhancerByCGLIB$$17779aa4() {
 CGLIB$BIND_CALLBACKS(this);
 }

 public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
 CGLIB$THREAD_CALLBACKS.set(var0);
 }

 public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
 CGLIB$STATIC_CALLBACKS = var0;
 }

 private static final void CGLIB$BIND_CALLBACKS(Object var0) {
 OrderServiceImpl$$EnhancerByCGLIB$$17779aa4 var1 = (OrderServiceImpl$$EnhancerByCGLIB$$17779aa4)var0;
 if(!var1.CGLIB$BOUND) {
  var1.CGLIB$BOUND = true;
  Object var10000 = CGLIB$THREAD_CALLBACKS.get();
  if(var10000 == null) {
  var10000 = CGLIB$STATIC_CALLBACKS;
  if(CGLIB$STATIC_CALLBACKS == null) {
  return;
  }
  }

  var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
 }

 }

 public Object newInstance(Callback[] var1) {
 CGLIB$SET_THREAD_CALLBACKS(var1);
 OrderServiceImpl$$EnhancerByCGLIB$$17779aa4 var10000 = new OrderServiceImpl$$EnhancerByCGLIB$$17779aa4();
 CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
 return var10000;
 }

 public Object newInstance(Callback var1) {
 CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
 OrderServiceImpl$$EnhancerByCGLIB$$17779aa4 var10000 = new OrderServiceImpl$$EnhancerByCGLIB$$17779aa4();
 CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
 return var10000;
 }

 public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
 CGLIB$SET_THREAD_CALLBACKS(var3);
 OrderServiceImpl$$EnhancerByCGLIB$$17779aa4 var10000 = new OrderServiceImpl$$EnhancerByCGLIB$$17779aa4;
 switch(var1.length) {
 case 0:
  var10000.<init>();
  CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
  return var10000;
 default:
  throw new IllegalArgumentException("Constructor not found");
 }
 }

 public Callback getCallback(int var1) {
 CGLIB$BIND_CALLBACKS(this);
 MethodInterceptor var10000;
 switch(var1) {
 case 0:
  var10000 = this.CGLIB$CALLBACK_0;
  break;
 default:
  var10000 = null;
 }

 return var10000;
 }

 public void setCallback(int var1, Callback var2) {
 switch(var1) {
 case 0:
  this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
 default:
 }
 }

 public Callback[] getCallbacks() {
 CGLIB$BIND_CALLBACKS(this);
 return new Callback[]{this.CGLIB$CALLBACK_0};
 }

 public void setCallbacks(Callback[] var1) {
 this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
 }

 static {
 CGLIB$STATICHOOK1();
 }
}

上面的代码可以看到代理类OrderServiceImpl$$EnhancerByCGLIB$$17779aa4 继承目标类OrderServiceImpl并且实现了接口Factory,代理类中关于createorder生成了两个方法CGLIB$createOrder$0和createOrder:

CGLIB$createOrder$0方法内部直接调用目标类的supper.createOrder

createOrder方法内部首先盘点否实现了MethodInterceptor接口的callback,如果存在则调用MethodInterceptor接口拦截方法intercept,根据前面的实现intercept方法内部实现了对目标方法的调用Object o1 = arg3.invokeSuper(arg0, arg2) ,invokeSuper内部实际上是直接调用的代理类的CGLIB$createOrder$0()方法,最终调用了目标类createOrder。

两种代理对比

JDK动态代理:

代理类与委托类实现同一接口,主要是通过代理类实现InvocationHandler并重写invoke方法来进行动态代理的,在invoke方法中将对方法进行增强处理  优点:不需要硬编码接口,代码复用率高,缺点:只能够代理实现了接口的委托类

CGLIB动态代理:

代理类将委托类作为自己的父类并为其中的非final委托方法创建两个方法,一个是与委托方法签名相同的方法,它在方法中会通过super调用委托方法;另一个是代理类独有的方法。在代理方法中,它会判断是否存在实现了MethodInterceptor接口的对象,若存在则将调用intercept方法对委托方法进行代理  优点:可以在运行时对类或者是接口进行增强操作,且委托类无需实现接口,缺点:不能对final类以及final方法进行代理

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • spring-boot使用AOP统一处理日志

    AOP我想大家都很清楚,有时候我们需要处理一些请求日志,或者对某些方法进行一些监控,如果出现例外情况应该进行怎么样的处理,现在,我们从spring-boot中引入AOP. [开发环境:jdk版本号为1.8,spring boot的版本号为1.4.1]{style="background-color:#FF0000"} 首先,我们先引入jar包, POM文件添加如下内容: <!--引用AOP--> <dependency> <groupId>org.s

  • spring基础概念AOP与动态代理理解

    一.代理模式 代理模式的英文叫做Proxy或Surrogate,中文都可译为"代理",所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 以简单模拟事务的执行过程说明各种代理区别 1.1 静态代理 由程序员创建或由特定工具自动生成源代码,再对其编译.在程序运行前,代理类的.class文件就已经存在了. public interface PersonDao { vo

  • 实例讲解Java的Spring框架中的AOP实现

    简介 面向切面编程(AOP)提供另外一种角度来思考程序结构,通过这种方式弥补了面向对象编程(OOP)的不足. 除了类(classes)以外,AOP提供了 切面.切面对关注点进行模块化,例如横切多个类型和对象的事务管理. (这些关注点术语通常称作 横切(crosscutting) 关注点.) Spring的一个关键的组件就是 AOP框架. 尽管如此,Spring IoC容器并不依赖于AOP,这意味着你可以自由选择是否使用AOP,AOP提供强大的中间件解决方案,这使得Spring IoC容器更加完善

  • 利用spring aop实现动态代理

    下面由我来给大家展示用spring aop实现动态代理的例子(电脑打印) 下面就看一下具体的代码: 先定义一个打印机的接口 package aop007_ComPrint; public interface Print { public void ColorPrint(); //彩色打印 public void WhitePrint(); //黑白打印 } 然后定义两个实现类,分别实现彩色打印和黑白打印 package aop007_ComPrint; public class ColorPri

  • 深入浅析Spring 的aop实现原理

    什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入封装.继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合.当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力.也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系.例如日志功能.日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无

  • Spring AOP代理详细介绍

    Spring AOP代理详细介绍 前言: 一开始我对spring AOP还是属于一知半解的状态,这几天遇到一个问题,加上又查看了一些Spring相关知识,感觉对这个问题有了更深刻的认识.所以写下来分享一下. 我们知道,Spring支持多种AOP方式,Spring自己的基于代理的AOP和AspectJ的基于编织(weaving)的AOP.如果一个类实现了一个或多个接口,那么Spring就会使用默认的JDK动态代理,如果没有实现任何接口,就会使用cglib来代理.当然我们也可以手动改变这些设置.这也

  • 详解SpringBoot AOP 拦截器(Aspect注解方式)

    常用用于实现拦截的有:Filter.HandlerInterceptor.MethodInterceptor 第一种Filter属于Servlet提供的,后两者是spring提供的,HandlerInterceptor属于Spring MVC项目提供的,用来拦截请求,在MethodInterceptor之前执行. 实现一个HandlerInterceptor可以实现接口HandlerInterceptor,也可以继承HandlerInterceptorAdapter类,两种方法一样.这个不在本文

  • Spring AOP注解失效的坑及JDK动态代理

    @Transactional @Async等注解不起作用 之前很多人在使用Spring中的@Transactional, @Async等注解时,都多少碰到过注解不起作用的情况. 为什么会出现这些情况呢?因为这些注解的功能实际上都是Spring AOP实现的,而其实现原理是通过代理实现的. JDK动态代理 以一个简单的例子理解一下JDK动态代理的基本原理: //目标类接口 public interface JDKProxyTestService { void run(); } //目标类 publ

  • Spring AOP拦截-三种方式实现自动代理详解

    这里的自动代理,我讲的是自动代理bean对象,其实就是在xml中让我们不用配置代理工厂,也就是不用配置class为org.springframework.aop.framework.ProxyFactoryBean的bean. 总结了一下自己目前所学的知识. 发现有三种方式实现自动代理 用Spring一个自动代理类DefaultAdvisorAutoProxyCreator: <bean class="org.springframework.aop.framework.autoproxy.

  • Spring温故而知新系列教程之AOP代理

    AOP的概念 AOP:Aspect-Oriented Programming(面向切面编程),维基百科的解释如下:Aspect是一种新的模块化机制,用来描述分散在对象.类或者函数中的横切关注点,从关注点中分离出横切关注点是面向切面的程序设计的核心概念.分离关注点使解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑的代码中不在含有针对特定领域问题的代码的调用,业务逻辑同特定领域问题的关系通过切面来封装.维护,这样原本分散在整个应用程序中的变动就可以很好地管理起来.从AOP的角度,应用可以分为横切

  • Spring Boot系列教程之7步集成RabbitMQ的方法

    前言 RabbitMQ是一种我们经常使用的消息中间件,RabbitMQ是实现AMQP(高级消息队列协议)的消息中间件的一种,最初起源于金融系统,用于在分布式系统中存储转发消息,在易用性.扩展性.高可用性等方面表现不俗.RabbitMQ主要是为了实现系统之间的双向解耦而实现的.当生产者大量产生数据时,消费者无法快速消费,那么需要一个中间层.保存这个数据. AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件

  • SpringBoot系列教程之dubbo和Zookeeper集成方法

    今日学习新的内容:dubbo   dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,一款高性能.轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现. zookeeper   zooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护.域名服务.分布式同步.组服务等. SpringBoot整合dubbo和Zookeeper 1.了解Dubbo基本

  • SpringBoot开发教程之AOP日志处理

    目录 日志处理: 需求分析 实现过程: 实验效果: 参考文献: 总结 日志处理: 需求分析 日志处理需要记录的是: 请求的URL 访问者IP 调用的方法 传入的参数 返回的内容 上面的内容要求在控制台和日志中输出. 在学习这部分知识的时候,真的感觉收获很多,在之前Spring学习的aop只是初步了解,现在有了一些深入的理解.好记性不如烂笔头! 在日志处理这部分主要是aop的使用,通过切面的方式来整合到项目了,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率. 人话

  • java JDBC系列教程之JDBC类的简析与JDBC的基础操作

    什么是JDBC? 概念:JAVA Database Connectivity Javas数据库连接,Java语言操作数据库接口,然后由各个数据库厂商去实现这个接口,提供数据库驱动java包,我们可以使用这套接口,真正执行的是jar驱动包中的实习类 使用一张图让大家更为直观的理解: coder就是写这套接口的程序员 JDBC的使用步骤 1.导入驱动jar包 2.注册驱动 3.获取数据库连接对象 4.定义sql执行语句 5.获取sql语句执行对象 6.执行sql语句返回结果 7.处理结果 8.释放结

  • Spring学习教程之AOP模块的概述

    概述 spirng-aop模块是Spring框架中的核心模块,虽然Spring Ioc container并不依赖AOP,但AOP给Ioc的实现提供了一种强大而灵活的解决方案. 在Spring Framework中,AOP主要是用于两种目的: 提供一些 企业 级的声明式服务,典型的应用如 declarative transaction management . 允许用户实现自己的aspects,用AOP的方式来帮助和补充OOP的功能及实现 AOP从功能的角度来讲,可能看作OOP编程方式的一种补充

  • Spring Cloud入门教程之Zuul实现API网关与请求过滤

    简介 Zuul是Netflix基于JVM的路由器和服务器端负载均衡器.最常用的场景是替换Nginx反向代理后台微服务供前端UI访问. Zuul使用Ribbon来定位一个通过发现转发的实例,所有请求都以hystrix命令执行,所以故障将显示在Hystrix指标中. 注:Zuul不包括发现客户端,因此对于基于服务ID的路由,需要在类路径中提供其中一个路由 Zuul是Spring Cloud提供的api网关和过滤组件,它提供如下功能: 认证 过滤 压力测试 Canary测试 动态路由 服务迁移 负载均

  • Spring装配Bean教程之XML安装配置bean详解

    前言 众所周知在Spring刚出现的时候,XML是描述配置的主要方式,在Spring的名义下,我们创建了无数行XML代码.在一定程度上,Spring成为了XML的同义词. 现在随着强大的自动化配置和Java代码的配置出现,XML不再是唯一选择,也不应该是首选,学习XML配置,更多用于维护已有的XML的配置.下面话不多说了,来一起看看详细的介绍吧. 创建XML配置规范 在使用XML配置前,需要创建一个新的配置规范,就像JavaConfig需要我们创建带有 @Configuration注解的类,而在

  • Spring Boot高级教程之Spring Boot连接MySql数据库

    Spring Boot可以大大简化持久化任务,几乎不需要写SQL语句,在之前章节"Spring Boot 构建框架"中我们新建了一个Spring Boot应用程序,本章在原有的工程中与数据库建立连接. Spring Boot有两种方法与数据库建立连接,一种是使用JdbcTemplate,另一种集成Mybatis,下面分别为大家介绍一下如何集成和使用这两种方式. 1. 使用JdbcTemplate <dependency> <groupId>mysql</g

  • spring cloud学习教程之config修改配置详解

    之前我们讲过了spring cloud之config配置的相关内容,那么在Git端修改配置后如何让客户端生效?下面来一起看看详细的介绍吧. 访问接口修改 refresh post方式执行http://localhost/refresh 会刷新env中的配置 restart 如果配置信息已经注入到bean中,由于bean是单例的,不会去加载修改后的配置 需要通过post方式去执行http://localhost/restart, 需要通过application.properties中配置endpo

随机推荐