静态代理
代理类自己编写,在编译器已经确认了代理类。
实现步骤
1.定义接口及其实现类
public interface SayHelloService { void say(); } public class SayHelloServiceImpl implements SayHelloService { @Override public void say() { System.out.println("Hello Bitch"); } }
2.定义类代理对象
public class SayHelloServiceProxy implements SayHelloService { private SayHelloService target; public SayHelloServiceProxy(SayHelloService service) { this.target = service; } @Override public void say() { System.out.println("记录日志。。。。。。"); target.say(); System.out.println("清理数据。。。。。。"); } public static void main(String[] args) { SayHelloServiceProxy proxy = new SayHelloServiceProxy(new SayHelloServiceImpl()); proxy.say(); } }
代理类实现了目标对象的接口,对原有得接口做了扩展,其中所有的对象都是在编译期都确定好了。
缺点
需要代理对象实现目标对象的接口,假如目标对象方法很多或者需要代理多个对象,复杂度就会很高。
而动态代理不需要在编译期确定代理类,可以在运行时期动态生成,反射是动态代理的一种实现方式。
java中的动态代理
主要由以下两种方式实现:
JDK动态代理
JDK动态代理需要目标对象实现一个或多个接口,否则只能使用CGLIB实现动态代理。
实现步骤
1.定义目标类和公共接口
public interface UserService { void add(); } public class UserServiceImpl implements UserService { @Override public void add() { // TOD Auto-generated method stub System.out.println("-------add--------"); } }
2.定义调用处理器类,可以再运行时生成代理类,并带上一些增强的功能
java.lang.reflect.Proxy : 这是生成代理类的主类,通过 Proxy 类生成的代理类都继承了 Proxy 类,即 DynamicProxyClas extends Proxy。
java.lang.reflect.InvocationHandler:调用处理类
public class MyInvocationHandler implements InvocationHandler { private Object target; public MyInvocationHandler(Object target) { super(); this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("------begin " + method.getName() + "------"); Object result = method.invoke(target, args); System.out.println("------end " + method.getName() + "-------"); return result; } public Object getProxy() { return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this); } public static void main(String[] args) { UserService service = new UserServiceImpl(); MyInvocationHandler handler = new MyInvocationHandler(service); UserService proxy = (UserService) handler.getProxy(); proxy.add(); } }
原理解析
上面关键点在于Proxy.newProxyInstance() 方法创建了一个代理对象,查看他的源码,封装了创建代理类及对象的方法,如下:
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. */ Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } 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); } }
其中的getProxyClass0(loader, intfs)实际生成了代理类,这个代理类是动态代理的关键,因为是在运行时动态生成的,我们可以通过下面的方法将生成的文件显示出来,探探究竟
public static void main(String[] args) throws IOException { byte[] testProxies = ProxyGenerator.generateProxyClass("Proxy0", UserServiceImpl.class.getInterfaces()); String path = "E:/userProxies.class"; FileOutputStream fileOutputStream = new FileOutputStream(path); fileOutputStream.write(testProxies); fileOutputStream.flush(); fileOutputStream.close(); }
反编译生成的文件如下
public final class Proxy0 extends Proxy implements UserService { private static Method m1; private static Method m2; private static Method m3; private static Method m0; public Proxy0(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final void add() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode() throws { try { return (Integer)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m2 = Class.forName("java.lang.Object").getMethod("toString"); m3 = Class.forName("org.example.proxy.inter.UserService").getMethod("add"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
分析:jdk动态生成了一个代理类,继承于Proxy,当我们调用add()方法时,将此方法当做参数传了进去,super.h.invoke(this, m3, (Object[])null)。 最终调用了InvocationHandler的invoke方法。
InvocationHandler的invoke:
public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { Class<?> caller = Reflection.getCallerClass(); checkAccess(caller, clazz, obj, modifiers); } } MethodAccessor ma = methodAccessor; // read volatile if (ma == null) { ma = acquireMethodAccessor(); } return ma.invoke(obj, args); }
通过反射,得到被代理对象的方法实现。
一整套下来,达到了代理的功能。
Cglib动态代理
Cglib 是一个强大的高性能的代码生成包,它可以在运行期扩展 Java 类与实现 Java接口。
public class CglibProxy implements MethodInterceptor { private Enhancer enhancer = new Enhancer(); public Object getProxy(Class clazz) { //设置需要创建子类的类 enhancer.setSuperclass(clazz); enhancer.setCallback(this); //通过字节码技术动态创建子类实例 return enhancer.create(); } //实现 MethodInterceptor接口方法 @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("前置代理"); //通过代理类调用父类中的方法 Object result = methodProxy.invokeSuper(obj, args); System.out.println("后置代理"); return result; } public static void main(String[] args) { CglibProxy proxy = new CglibProxy(); //通过生成子类的方式创建代理类 UserServiceImpl proxyImp = (UserServiceImpl) proxy.getProxy(UserServiceImpl.class); proxyImp.add(); } }
二者区别
使用动态代理的对象必须实现一个或多个接口
使用 cglib 代理的对象则无需实现接口,达到代理类无侵入。
SpringAOP
主要由JDK动态代理和CGLIB动态代理实现
JDK 动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK 动态代理的核心是 InvocationHandler 接口和 Proxy 类。如果目标类没有实现接口,那么 Spring AOP 会选择使用 CGLIB 来动态代理目标类。
CGLIB(Code Genration Libray),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,CGLIB 是通过继承的方式做的动态代理,因此如果某个类被标记为 final,那么它是无法使用 CGLIB 做动态代理的。