怎么创建网站要钱吗,百度网址大全下载安装,网站设计公司 无锡,贵阳网站建设多少钱java有三种代理模式
静态代理
jdk动态代理
cglib实现动态代理 代理模式的定义#xff1a; 为其他对象提供一种代理以控制对这个对象的访问。在某些情况下#xff0c;一个对象不适合或者不能直接引用另一个对象#xff0c;而代理对象可以在客户端和目标对象之间起到中介的…java有三种代理模式
静态代理
jdk动态代理
cglib实现动态代理 代理模式的定义 为其他对象提供一种代理以控制对这个对象的访问。在某些情况下一个对象不适合或者不能直接引用另一个对象而代理对象可以在客户端和目标对象之间起到中介的作用。 java的三种代理模式优缺点 静态代理jdk动态代理 cglib实现动态代理 优 点 简单易懂静态代理模式的实现相对简单易于理解和使用。代理类在编译时就已经存在开发人员可以直接通过编码方式创建和配置代理对象。 可以在代理类中添加额外的逻辑通过静态代理我们可以在代理类中添加额外的逻辑如安全检查、日志记录、性能监控等而无需修改被代理类的代码。这种方式使得代理类具有更高的灵活性和扩展性。 控制访问权限静态代理可以控制对被代理对象的访问权限。代理类可以添加一些条件或限制以决定是否调用被代理类的方法从而实现对被代理对象的权限控制。 低耦合通过静态代理被代理类和代理类是相互独立的彼此并无直接的依赖关系。这种低耦合的设计能够降低系统的复杂性提高代码的可维护性和可测试性。 可以对多个对象进行代理静态代理模式可以对多个对象进行代理这样我们可以在不改变原始对象的情况下通过代理对象来进行统一的管理和控制。 简化代理模式实现相比于静态代理JDK动态代理通过反射机制实现无需手动编写大量的代理类代码。只需要编写一个代理处理器即可大大简化了代理模式的实现过程。 可以代理任意接口JDK动态代理是基于接口的代理可以代理任意实现了接口的类。这意味着无论被代理类的具体实现如何只要实现了接口就可以使用JDK动态代理进行代理操作。 代码结构清晰使用JDK动态代理代理类和被代理类之间的关系更加清晰。代理类实现了InvocationHandler接口可以在方法调用前后添加自定义逻辑而被代理类则专注于核心业务逻辑的实现。这样有利于代码的维护和扩展。 可以动态改变代理行为由于代理类是在运行时动态生成的可以在代理类中灵活地修改和调整代理行为。可以根据实际需要在不修改被代理类代码的情况下通过修改代理处理器的逻辑实现不同的代理行为。 高性能相比于CGlib等其他动态代理实现JDK动态代理在性能上具有较好的表现。JDK动态代理使用Java原生的反射机制在执行方法调用时会有一些性能损耗但仍然比一些其他动态代理实现方式更高效。 无需接口CGLib可以为非接口类生成代理这意味着我们可以代理那些没有实现任何接口的类。相比于JDK动态代理需要目标类实现接口的限制CGLib的使用更加灵活。 高性能CGLib采用了底层的字节码操作技术通过生成目标类的子类并重写其中的方法来实现代理。相比于JDK动态代理的反射调用CGLib的代理调用更快速性能更高效。 简化代理CGLib可以在运行时生成代理类避免了编写很多重复的代理类代码的麻烦。它通过继承来实现代理这样我们就可以专注于业务逻辑的实现而无需关心代理类的创建和管理。 支持回调过滤CGLib提供了MethodInterceptor接口可以在代理类的方法调用前后插入自定义的逻辑。这允许我们在目标方法执行前后进行一些额外的处理如日志记录、权限校验、缓存等。 可扩展性强CGLib是一个功能强大的库除了可以实现动态代理外还可以用于AOP编程、实现Bean的动态注入等。它提供了丰富的API和扩展点可以根据实际需求进行灵活的扩展和定制。 缺 点 代码复杂度增加使用静态代理会引入额外的代理类从而增加代码的复杂性。每个被代理类都需要对应一个代理类随着被代理类的增加代理类的数量也会增加导致代码变得冗长且难以维护。 频繁更新代理类如果被代理类的接口发生变化代理类也需要相应地进行修改。这意味着在使用静态代理时每次接口发生变动需要手动更新相关的代理类增加了维护成本和风险。 静态代理不支持动态代理静态代理是在编译时期生成的代理类对于动态生成的对象无法进行代理。如果需要对一批动态生成的对象进行代理静态代理就显得无能为力。 单一职责原则破坏静态代理中代理类与被代理类紧密耦合代理类不仅要实现接口方法的委托还要添加额外的逻辑。这样可能导致代理类承担了过多的责任违反了单一职责原则。 动态扩展困难静态代理在代理类定义时就已经确定了被代理对象如果需要代理新的类或者对象就要重新编写对应的代理类。这种静态的特性使得动态扩展变得困难难以应对频繁变化的需求。 只能代理接口JDK动态代理只能代理实现了接口的类对于没有实现接口的类无法进行代理。这一限制使得某些类无法使用JDK动态代理需要考虑其他代理实现方式。 性能有一定损耗JDK动态代理使用反射机制在方法调用时会涉及到反射操作这会引入一定的性能损耗。相比起静态代理JDK动态代理的性能稍差一些。对于对性能要求较高的场景可能需要考虑其他更高效的代理实现方式。 无法代理私有方法JDK动态代理只能代理公开的方法无法代理私有方法。这是由于代理机制是基于接口生成的动态代理类无法直接访问类的私有成员。 需要实现InvocationHandler接口使用JDK动态代理需要编写一个实现InvocationHandler接口的代理处理器类。虽然这使得动态代理实现更加灵活但同时也增加了开发的复杂性。 无法直接修改被代理类JDK动态代理是通过代理接口生成代理类而不是直接修改被代理类的字节码。这一特性使得在不修改被代理类的情况下无法对其进行修改或添加新的行为。 类加载器限制CGLib使用了底层的字节码操作技术来生成代理类这需要在运行时动态创建和加载类。某些情况下类加载器限制可能会导致无法使用CGLib动态代理例如在一些受限的环境下或者使用特定的类加载器。 需要依赖第三方库CGLib是一个第三方库不是Java的标准库。使用CGLib时需要将其引入项目中并进行相应的配置增加了项目的依赖。 Proxy无法代理final方法CGLib的动态代理无法代理final方法因为final方法无法被子类重写。如果目标类中存在final方法CGLib将无法为其生成代理这在一些特定场景下可能会有限制。 难以调试使用CGLib生成的代理类是动态生成的字节码对于开发者来说可读性较差。对于调试代理类的问题或者理解代理逻辑可能需要额外的工具和技巧。 内存占用较高由于CGLib是通过生成代理类的子类来实现的每次代理都会创建一个新的类并加载到JVM中。如果频繁地创建代理对象可能会产生大量的代理类增加内存占用。 静态代理
先创建一个父类或者接口被代理对象和代理对象都应该继承父类或者实现接口。 创建接口Movie.java
public interface Movie {void play();
}创建实现类RealMovie.java
public class RealMovie implements Movie {Overridepublic void play() {System.out.println(播放金刚大战哥斯拉);}
}创建代理类ProxyMovie.java
public class ProxyMovie implements Movie {Movie movie;public ProxyMovie(Movie movie) {this.movie movie;}Overridepublic void play() {System.out.println(电影还没开始买点爆米花);movie.play();System.out.println(电影结束了买个哥斯拉模型);}
}创建测试类Test.java
public class Test {public static void main(String[] args) {RealMovie movie new RealMovie();ProxyMovie proxyMovie new ProxyMovie(movie);proxyMovie.play();}
}总结在不改变RealMovie的前提下使用ProxyMovie对其进行了增强。但是由于目标对象和代理对象都实现了同一个接口一旦这个接口添加或者删除方法那么代理对象和目标对象都要进行相应的操作耦合度太高。 静态代理的应用在使用实现Runnable接口实现多线程的时候将Runnable接口的实现类的对象作为Thread的构造函数的参数 jdk动态代理
为了解决静态代理的代理类必需实现接口的所有方法的问题动态代理诞生了java的动态代理有如下的特点 1、代理对象不需要跟目标对象实现同一接口或继承同一个父类解决了静态代理的痛点 2、代理对象的生成利用jdk提供的api在JVM内存中动态的构建代理对象。 创建接口Movie.java
public interface Movie {void play();
}创建实现类RealMovie.java
public class RealMovie implements Movie{Overridepublic void play() {System.out.println(播放侏罗纪世界);}
}创建代理类ProxyMovie.java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class ProxyMovie implements InvocationHandler {private Object movie;public ProxyMovie(Object movie) {this.movie movie;}Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println(电影还没开始买瓶可乐);method.invoke(movie, args);System.out.println(电影还结束买一只恐龙模型);return null;}
}创建测试类Test.java
public class Test {public static void main(String[] args) {RealMovie realMovie new RealMovie();InvocationHandler proxyMovie new ProxyMovie(realMovie);// 创建代理对象Movie movie (Movie)Proxy.newProxyInstance(realMovie.getClass().getClassLoader(), realMovie.getClass().getInterfaces(), proxyMovie);System.out.println(movie.getClass().getSimpleName());movie.play();}
}总结在这里代理类没有实现Movie接口而是实现了InvocationHandler接口然后重写了invoke方法与Movie接口的耦合度降低。
cglib实现动态代理
在使用jdk动态代理时被代理对象是实现了一个接口的假如实际中被代理对象没有实现接口该怎么办呢cglib动态代理便应运而生原理是创建一个目标对象的子类对象然后进行增强操作所以被代理对象的类不能是final类型的无法被继承也就没有子类被调用的方法也不能是final和static类型的不会执行代理功能。 在pom.xml文件中添加cglib依赖
dependencygroupIdcglib/groupIdartifactIdcglib/artifactIdversion3.3.0/version
/dependency创建CglibService.java
public class CglibService {public void movie() {System.out.println(播放侏罗纪公园);}
}创建CglibServiceProxy.java类
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class CglibServiceProxy implements MethodInterceptor {private Object object;public CglibServiceProxy(Object object) {this.object object;}public Object getProxyInstance() {//创建代理类Enhancer enhancer new Enhancer();//继承要被代理的类enhancer.setSuperclass(object.getClass());//设置回调函数enhancer.setCallback(this);return enhancer.create();}Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println(电影即将开始大家有序进入影厅);Object obj method.invoke(object);System.out.println(电影结束大家离开电影院);return obj;}
}创建CglibProxyTest.java
public class CglibProxyTest {public static void main(String[] args) {CglibService service new CglibService();CglibServiceProxy proxy new CglibServiceProxy(service);CglibService proxyInstance (CglibService)proxy.getProxyInstance();proxyInstance.movie();}
}总结由以上可以看出使用cglib代理可以代理一些没有父类的目标对象所以以后如果要代理没有实现接口的类可以选择使用cglib代理。