郑州网站建设公司怎么选,建设部网站官网合同,南京建设网站,北京网站维护浩森宇特✅Java动态代理如何实现 ✅JDK动态代理和Cglib动态代理的区别 ✅拓展知识仓✅静态代理和动态代理的区别✅动态代理的用途✅Spring AOP的实现方式#x1f4d1;JDK 动态代理的代码段#x1f4d1;Cglib动态代理的代码块 ✅注意事项#xff1a; 在Java中#xff0c;实现动态代理… ✅Java动态代理如何实现 ✅JDK动态代理和Cglib动态代理的区别 ✅拓展知识仓✅静态代理和动态代理的区别✅动态代理的用途✅Spring AOP的实现方式JDK 动态代理的代码段Cglib动态代理的代码块 ✅注意事项 在Java中实现动态代理有两种方式: 1 . JDK动态代理 : Java.lang.reflect 包中的Proxy类和 InvocationHandler 接口提供了生成动态代理类的能力。 2 . Cglib动态代理 : Cglib (Code Generation Library) 是一个第三方代码生成类库运行时在内存中动态生成一个了类对象从而实现对目标对象功能的扩展。 用一张图片看一下什么是动态代理概念 ✅JDK动态代理和Cglib动态代理的区别 JDK的动态代理有一个限制就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的类就可以使用CGLIB实现。 Cglib是一个强大的高性能的代码生成包它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用例如Spring AOP和dynaop为他们提供方法的 interception (拦截)。 Calib包的底层是通过使用一个小而快的字节码处理框架ASM来转换字节码并生成新的类。不鼓励直接使用ASM因为它需要你对JVM内部结构包括class文件的格式和指令集都很熟悉。 所以使用JDK动态代理的对象必须实现一个或多个接口:而使用cgib代理的对象则无需实现接口达到代理类无侵入。 ✅拓展知识仓
✅静态代理和动态代理的区别 最大的区别就是静态代理是编译期确定的但是动态代理却是运行期确定的。 同时使用静态代理模式需要程序员手写很多代码这个过程是比较浪费时间和精力的。一旦需要代理的类中方法比较多或者需要同时代理多个对象的时候这无疑会增加很大的复杂度。 反射是动态代理的实现方式之一。 ✅动态代理的用途 Java的动态代理在日常开发中可能并不经常使用但是并不代表他不重要。Java的动态代理的最主要的用途就是应用在各种框架中。因为使用动态代理可以很方便的运行期生成代理类通过代理类可以做很多事情比如AOP比如过滤器、拦截器等。 在我们平时使用的框架中像 servlet 的 filter 、包括 spring 提供的 aop 以及 struts2 的拦截器都使用了动态代理功能。我们日常看到的mybatis分页插件以及日志拦截、事务拦截、权限拦截这些几乎全部由动态代理的身影。 ✅Spring AOP的实现方式 Spring AOP中的动态代理主要有两种方式JDK动态代理和CGLIB动态代理。 JDK 动态代理通过反射来接收被代理的类并且要求被代理的类必须实现一个接口。JDK 动态代理的核心是 InvocationHandler 接 和 Proxy 类。 如果目标类没有实现接口那么Spring AOP会选择使用CGLIB来动态代理目标类。 CGLIB (Code Generation Library)是一个代码生成的类库可以在运行时动态的生成某个类的子类注意CGLIB是通过继承的方式做的动态代理因此如果某个类被标记为final那么它是无法使用CGLIB做动态代理的。 JDK 动态代理的代码段 public class UserServiceImpl implements UserService {Overridepublic void add() {// TODO Auto-generated method stubSystem,out,println(--------------------add----------------------);}
}public class MyInvocationHandler implements InvocationHandler {private Object target;public MyInvocationHandler(Object target) {super();this.target target;}Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {PerformanceMonior.begin(target.getClass().getlame( )method.getlame());//System.out .println(-----------------begin “method.getName()---------);Object result method.invoke(target, args);//System.out.println(--------------end method.getName( )-----);PerformanceMonior.end();return result;}public Object getProxy() {return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(),this);}
}public static void main(string[] args) {UserService seryice new UserServiceImpl();MyInvocationHandler handler new MyInvocationHandler(service);UserService proxy (UserService) handler.getProxy();proxy .add();
}Cglib动态代理的代码块 public class UserServiceImpl implements UserService {Overridepublic void add() {//TODO Auto-generated method stubSystem.out,println(--------------------add----------------------);}}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接口方法public Object intercept(Object obj,Method method, Object[] args,MethodProxy proxy) throws Throwable {System.out.println(前置代理);//通过代理类调用父类中的方法Object result proxy.invokeSuper(obj, args);System.out.printIn(后置代理);return result;}
}public class DoCGLib {public static void main(String[] args) {CglibProxy proxy new CglibProxy();//通过生成子类的方式创建代理类UsenServiceImpl proxyImp (UsenServiceImpl)proxy.getProxy(UserServiceImpl.class);proxyImp.add():}
}✅注意事项 JDK动态代理只能用于接口不能用于类。 动态代理只对方法调用有效对字段访问和赋值无效。如果目标对象抛出了异常那么这个异常会被代理对象抛出而不是在调用invoke方法时抛出。 与CGLIB等其他代理技术的比较 CGLIB它是一个强大的高性能的代码生成库可以扩展JAVA类和实现JAVA接口。它主要应用于高级OOP设计和应用如AOP实现、缓存框架、事务管理等。两者的选择如果你的目标是基于现有类的行为进行拦截或修改可以使用CGLIB如果目标是基于接口进行拦截或修改那么应该使用JDK动态代理。 思考 除了JDK动态代理和CGLIB还有其他一些常用的代理技术如Spring AOP、AspectJ等。这些技术提供了更高级的特性如支持方法级别的拦截、支持运行时和编译时切面等。 // 导入java.lang.reflect包中的InvocationHandler和Proxy类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy; // 定义一个接口Hello
interface Hello { // 定义接口方法sayHello没有实现 void sayHello();
} // 定义一个实现Hello接口的类HelloImpl
class HelloImpl implements Hello { // 实现接口方法sayHello public void sayHello() { System.out.println(Hello, world!); }
} // 定义一个实现InvocationHandler接口的类DynamicProxyHandler
class DynamicProxyHandler implements InvocationHandler { // 私有成员变量obj用来保存目标对象的引用 private Object obj; // 构造方法传入目标对象作为参数赋值给obj成员变量 public DynamicProxyHandler(Object obj) { this.obj obj; } // 实现InvocationHandler接口的方法invoke传入代理对象、方法、参数数组返回值类型为Object public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { // 在目标方法执行前输出Before method call System.out.println(Before method call); // 调用目标方法传入参数args返回值赋值给result变量 Object result m.invoke(obj, args); // 在目标方法执行后输出After method call System.out.println(After method call); // 返回目标方法的返回值或者异常如果目标方法抛出了异常 return result; }
} public class DynamicProxyExample { public static void main(String[] args) { // 创建一个HelloImpl类的实例作为目标对象并实现Hello接口的sayHello方法 Hello hello new HelloImpl(); // 创建一个DynamicProxyHandler类的实例作为InvocationHandler传入目标对象实例作为参数传入构造器中 InvocationHandler handler new DynamicProxyHandler(hello); /** 使用Proxy类的静态方法newProxyInstance创建代理对象实例传入目标对象的类加载器、目标对象的接口数组以及* InvocationHandler实例作为参数传入构造器中。返回的是代理对象实例类型为目标对象的接口类型。* 创建的代理对象实例可以直接像目标对象实例一样使用只不过它实现了所有接口中的方法。* 所有这些方法的调用最终会调用到我们提供的InvocationHandler实例中对应的invoke方法中去处理。* 这样我们就能够在不修改原有代码的基础上为某个对象提供额外行为操作* 也就是实现了在运行时动态扩展了某个类的行为功能操作即实现了AOP的功能。* 这样就达到了在不修改原有代码的基础上扩展了某个类的行为功能操作的目的。* 比如可以在目标对象方法执行前后添加额外的逻辑操作处理。此处因为动态代理的目标是Hello接口所以没有错误。*/ Hello proxy (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), new Class[] { Hello.class }, handler); }
}最后总结一下JDK动态代理的思想