最近在学习Spring AOP的代码,AOP的底层是通过代理机制进行实现的,在这里先学习代理机制;
(1)、jdk动态代理
jdk动态代理使用接口InvocationHander和Proxy类,其中接口InvocationHander中:
该接口中只用一个方法invoke,该方法有三个参数:
- proxy 该参数为代理类的实例
- method 被调用的方法对象
- args 调用method对象的方法参数
public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
类Proxy,Proxy(Class)
Proxy是 Java 动态代理机制的主类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。
Proxy 的静态方法 static InvocationHandler getInvocationHandler(Object proxy)
该方法用于获取指定代理对象所关联的调用处理器 static Class getProxyClass(ClassLoader loader, Class[] interfaces)
该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象 static boolean isProxyClass(Class cl)
该方法用于判断指定类对象是否是一个动态代理类 static Object newProxyInstance(ClassLoader loader, Class[] interfaces,InvocationHandler h)
- loader 指定代理类的ClassLoader加载器
- interfaces 指定代理类要实现的接口
- h: 表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上。
使用Java 动态代理的两个重要步骤
- 通过实现 InvocationHandler 接口创建自己的调用处理器;
- 通过为Proxy类的newProxyInstance方法指定代理类的ClassLoader 对象和代理要实现的interface以及调用处理器InvocationHandler对象 来创建动态代理类的对象;
以下以实例对jdk的动态代理进行说明
(a)、创建一个第三方的接口及类,用于进行动态代理实例说明
接口:
public interface SubjectService { void say(); }
相应的实现类:
public class SubjectServiceImpl implements SubjectService { public void say(){ System.out.println("开始说话"); } }
(b)、创建一个接口InvocationHandler的实现类
public class jdkProxy implements InvocationHandler { Object target; public jdkProxy(Object target){ this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName() == "say"){ System.out.println("说话之前"); method.invoke(target,args); System.out.println("说话之后"); } return null; } }
(c)、通过Proxy类创建代理对象,进行函数调用
public static void main(String[] args) { SubjectService subject = (SubjectService) Proxy.newProxyInstance(jdkProxy.class.getClassLoader(), SubjectService.class.getInterfaces(),new jdkProxy(new SubjectServiceImpl())); subject.say(); }
其中第二个参数SubjectService.class.getInterfaces(),还可以使用new Class[]{SubjectService.class}。
默认情况下,Spring Aop如果发现目标对象实现了相应的接口,就是使用动态代理的方式为目标对象生成一个代理对象,但是如果目标对象没有实现接口,那么只能使用一个CGLIB的开源动态字节码生成类库,为目标对象生成动态的代理对象实例。
(2)、动态字节码生成
原理:为目标对象进行扩展,为其生成相应的子类,而子类可以通过复写扩展父类的行为,只要将横切逻辑的实现放到子类中,然后让系统使用扩展后的目标对象的子类,就可以达到与代理模式相同的效果了。
借助CGLIB这样的字节码生成库,在系统运行期间可以动态的为目标对象生成相应的子类。
该接口继承了Callback接口,接口中只有一个方法 intercept(),该方法共有四个参数:
1)obj表示增强的对象,即实现这个接口类的一个对象;
2)method表示要被拦截的方法;
3)args表示要被拦截方法的参数;
4)proxy表示要触发父类的方法对象
public interface MethodInterceptor extends Callback { Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable; }
实例:
(a)、建立一个类
public class SubjectServiceImpl { public void say(){ System.out.println("开始说话"); } }
(b)、实现MethodInteceptor的类及相应的实现函数
public class CGLIB implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("吃饭之前"); methodProxy.invokeSuper(o,objects); System.out.println("吃饭之后"); return null; } public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(SubjectServiceImpl.class); enhancer.setCallback(new CGLIB()); SubjectServiceImpl subjectService = (SubjectServiceImpl) enhancer.create(); subjectService.say(); } }
引申学习,研究一下CGLIB的源码:
从enhancer.create()创建实例开始:
(1)、create()
/** * Generate a new class if necessary and uses the specified * callbacks (if any) to create a new object instance. * Uses the no-arg constructor of the superclass. * @return a new instance */ public Object create() { classOnly = false; argumentTypes = null; return createHelper(); }
(2)、createHelper()
private Object createHelper() { preValidate(); Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null, ReflectUtils.getNames(interfaces), filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter), callbackTypes, useFactory, interceptDuringConstruction, serialVersionUID); this.currentKey = key; Object result = super.create(key); return result; }
preValidate()方法校验callbackTypes、filter是否为空,以及为空时的处理。
(3)、create()
protected Object create(Object key) { try { ClassLoader loader = getClassLoader(); Map<ClassLoader, ClassLoaderData> cache = CACHE; ClassLoaderData data = cache.get(loader); if (data == null) { synchronized (AbstractClassGenerator.class) { cache = CACHE; data = cache.get(loader); if (data == null) { Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache); data = new ClassLoaderData(loader); newCache.put(loader, data); CACHE = newCache; } } } this.key = key; Object obj = data.get(this, getUseCache()); if (obj instanceof Class) { return firstInstance((Class) obj); } return nextInstance(obj); } catch (RuntimeException e) { throw e; } catch (Error e) { throw e; } catch (Exception e) { throw new CodeGenerationException(e); } }
(4)、nextInstance()
protected Object nextInstance(Object instance) { EnhancerFactoryData data = (EnhancerFactoryData) instance; if (classOnly) { return data.generatedClass; } Class[] argumentTypes = this.argumentTypes; Object[] arguments = this.arguments; if (argumentTypes == null) { argumentTypes = Constants.EMPTY_CLASS_ARRAY; arguments = null; } return data.newInstance(argumentTypes, arguments, callbacks); }
第一个参数为代理对象的构成器类型,第二个为代理对象构造方法参数,第三个为对应回调对象。
(5)、
看看data.newInstance(argumentTypes, arguments, callbacks)方法,
通过反射生成代理对象,源码如下:
/** * Creates proxy instance for given argument types, and assigns the callbacks. * Ideally, for each proxy class, just one set of argument types should be used, * otherwise it would have to spend time on constructor lookup. * Technically, it is a re-implementation of {@link Enhancer#createUsingReflection(Class)}, * with "cache {@link #setThreadCallbacks} and {@link #primaryConstructor}" * * @see #createUsingReflection(Class) * @param argumentTypes constructor argument types * @param arguments constructor arguments * @param callbacks callbacks to set for the new instance * @return newly created proxy */ public Object newInstance(Class[] argumentTypes, Object[] arguments, Callback[] callbacks) { setThreadCallbacks(callbacks); try { // Explicit reference equality is added here just in case Arrays.equals does not have one if (primaryConstructorArgTypes == argumentTypes || Arrays.equals(primaryConstructorArgTypes, argumentTypes)) { // If we have relevant Constructor instance at hand, just call it // This skips "get constructors" machinery return ReflectUtils.newInstance(primaryConstructor, arguments); } // Take a slow path if observing unexpected argument types return ReflectUtils.newInstance(generatedClass, argumentTypes, arguments); } finally { // clear thread callbacks to allow them to be gc'd setThreadCallbacks(null); } }
上述方法可以看出生成代理对象最终使用的是反射的方法进行获取。
在进行方法调用的时候,代理类中会调用拦截器函数,可以从字节码中看到相应代码。