Java Proxy And CGLIB Proxy
代理:能在目标方法执行前后或异常时做一些处理,并且可以多层代理,形成代理链
手动编码实现
interface Dao { void save(); } class DaoImpl implements Dao { @Override public void save() { System.out.println("save..."); } } class DaoProxy implements Dao{ private Dao target; public DaoProxy(Dao target) { this.target = target; } @Override public void save() { System.out.println("before..."); target.save(); System.out.println("after..."); } } public class StaticProxyTest { public static void main(String[] args) { DaoImpl target = new DaoImpl(); Dao userDao = new DaoProxy(target); userDao.save(); } }
JDK 动态代理(代理接口)
interface Dao { void save(); } class DaoImpl implements Dao { @Override public void save() { System.out.println("save..."); } } public class DynamicProxyTest { public static void main(String[] args) { Object target = new DaoImpl(); /** * loader:业务对象的类加载器 * interfaces:业务对象实现的所有的接口,可直接指定业务类实现的接口 Class[] * h:InvocationHandler 对象,最终由它调用业务对象的方法 * public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) */ Dao dao = (Dao) Proxy.newProxyInstance(DaoImpl.class.getClassLoader(), new Class<?>[]{Dao.class}, new InvocationHandler() { /** * @param proxy 代理对象 * @param method 代理的方法对象 * @param args 方法调用时参数 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; if (method.getName().equals("save")) { System.out.println("before..."); result = method.invoke(target, args); System.out.println("after..."); } return result; } }); dao.save(); } }
CGLIB(Code Generator Library)动态代理(代理类)
public class Dao { public void select() { System.out.println("select()"); } }
public class DaoProxy implements MethodInterceptor { /** * @param object 要进行增强的对象 * @param method 拦截的方法 * @param objects 参数列表,基本数据类型需要传入其包装类型 * @param proxy 对方法的代理,invokeSuper 方法表示对被代理对象方法的调用 */ @Override public Object intercept(Object object, Method method, Object[] objects, MethodProxy proxy) throws Throwable { System.out.println("Before Method Invoke"); proxy.invokeSuper(object, objects); System.out.println("After Method Invoke"); return object; } }
public static void main(String[] args) { DaoProxy daoProxy = new DaoProxy(); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Dao.class); enhancer.setCallback(daoProxy); Dao dao = (Dao) enhancer.create(); dao.select(); }
静态代理
静态代理是编译阶段生成 AOP 代理类,也就是说生成的字节码就织入了增强后的 AOP 对象,并不会创建出多余的对象
实现方式:
- 包装器模式:持有目标对象的引用,然后实际上是调用目标对象的方法。 这种方式也可称为代理模式,但是有明显的缺点(比如一般都需要实现同一个接口,且它是以编码的方式去实现的,侵入性高)
- AspectJ 静态代理方式:非常非常强大。AspectJ 并不是动态的在运行时生成代理类,而是在编译的时候就植入代码到 class 文件。由于是静态织入的,所以性能相对来说比较好。AspectJ 不受类的特殊限制,不管方法是 private、static 或 final 的,都可以代理,AspectJ 不会代理除了限定方法之外任何其他诸如 toString(),clone() 等方法,唯一缺点就是必须有 AspectJ 自己的编译器的支持,所以其实很少使用,Spring 也是提供了相关类支持,比如:LoadTimeWeaverAwareProcessor,基于 AspectJ 的静态代理方式非常强大,但是它依赖于它自己的编译器。并且还有自己的个性化语言,使用起来不够方便,因此其实还是使用得较少的。主要还是以动态代理为主
动态代理
动态代理不会修改字节码,而是在内存中临时生成一个 AOP 对象,这个 AOP 对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法
这在平时使用中得到了大量的应用,因为使用简单并且还非常灵活。
https://blog.csdn.net/f641385712/article/details/89362021
https://blog.csdn.net/f641385712/article/details/88952482