静态代理&动态代理
静态代理&动态代理
前言
本文为学习记录,可能有误请谅解…
1.代理模式
1.1何为代理模式
代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。代理是通过代理对象访问目标对象,从而实现在目标对象基础上增加额外的功能,例如日志记录、事务控制、性能监控等。减少重复代码、让代码复用性好。
分为静态代理和动态代理两种。
1.2为何要代理
Case1:没有目标类源码(java文件),或者是已经源码封装好了,无法直接操作到某个对象,但又必须和那个对象有所互动
Case2:只需要在某一处调用的地方进行额外功能添加,如果直接在目标类修改某个方法会导致所有调用该类此方法的逻辑都发生改变(牵一发而动全身)
2.静态代理与动态代理
2.1两者区别
静态代理与动态代理的区别在于是否生成class文件。使用静态代理是需要我们编写代理类,即最终在项目编译的文件中会看到class文件,而动态代理是动态生成字节码文件,在一些主流框架技术如spring、mybatis等使用了动态代理技术。
静态代理的实现方式有继承和聚合
动态代理的实现方式有JDK动态代理和Cglib动态代理
2.2静态代理——继承
继承方式的思想:使用代理类(子类)继承目标类(父类),然后重写目标类的方法,在重写方法内部调用目标类的方法,再增加代理的功能。
-
目标类
package com.proxy; /** * 目标类 * @author CMK * @date 2020-10-19 16:42 */ public class UserService { public void test(){ System.out.println("目标类方法执行......"); } }
-
代理类(继承目标类)
package com.proxy; /** * 代理类 * @author CMK * @date 2020-10-19 16:44 */ public class UserProxyService extends UserService { @Override public void test() { super.test(); //执行目标类方法 System.out.println("代理类方法执行......"); } }
-
运行测试类
package com.proxy; /** * 运行测试类 * @author CMK * @date 2020-10-19 16:46 */ public class Test { public static void main(String[] args) { UserService userService = new UserProxyService(); //此处使用了多态写法 userService.test(); //继承关系中子类有该方法则调用子类方法,没有则调用父类方法 } }
-
运行结果
2.3静态代理——聚合
聚合的思想:代理类和目标类实现了一个公共接口,创建代理对象时,通过构造方法或者set方法将目标对象进行聚合
-
公共接口
package com.proxy.aggregation; /** * 公共接口 * @author CMK * @date 2020-10-19 17:22 */ public interface Service { /** * 接口方法 */ void test(); }
-
目标类
package com.proxy.aggregation; /** * 目标类 * @author CMK * @date 2020-10-19 17:23 */ public class TargetService implements Service { /** * 目标类重写接口方法 */ @Override public void test() { System.out.println("目标类执行接口方法......"); } }
-
代理类(通过构造方法进行聚合)
package com.proxy.aggregation; /** * @author CMK * @date 2020-10-19 17:25 */ public class ProxyService implements Service { //将target目标对象当作代理类的一个成员属性 private Service target; //代理类构造方法 public ProxyService(Service target) { this.target = target; } /** * 代理类重写接口方法 */ @Override public void test() { //调用目标对象的方法 target.test(); //编写代理增加的方法 System.out.println("代理类方法执行......"); } }
-
运行测试类1
package com.proxy; import com.proxy.aggregation.ProxyService; import com.proxy.aggregation.Service; import com.proxy.aggregation.TargetService; /** * 运行测试类 * @author CMK * @date 2020-10-19 16:46 */ public class Test { public static void main(String[] args) { Service service = new ProxyService(new TargetService()); //通过创建目标类对象将其设置到代理类中 service.test(); } }
-
代理类(通过set方法进行聚合)
package com.proxy.aggregation; /** * @author CMK * @date 2020-10-19 17:25 */ public class ProxyService implements Service { //target目标对象 private Service target; //set方法 public void setTarget(Service target) { this.target = target; } /** * 代理类重写接口方法 */ @Override public void test() { //调用目标对象的方法 target.test(); //编写代理增加的方法 System.out.println("代理类执行接口方法......"); } }
-
运行测试类2
package com.proxy; import com.proxy.aggregation.ProxyService; import com.proxy.aggregation.Service; import com.proxy.aggregation.TargetService; /** * 运行测试类 * @author CMK * @date 2020-10-19 16:46 */ public class Test { public static void main(String[] args) { ProxyService proxyService = new ProxyService(); proxyService.setTarget(new TargetService()); proxyService.test(); } }
-
运行结果
2.4动态代理——JDK
JDK动态代理:基于接口的代理,必须有接口才可以代理。
-
接口
package com.proxy.service; /** * 接口 * @author CMK * @date 2020-10-19 19:11 */ public interface UserService { //接口方法 void test(); }
-
目标类(接口实现类)
package com.proxy.service.impl; import com.proxy.service.UserService; /** * 目标类(接口实现类) * @author CMK * @date 2020-10-19 19:13 */ public class UserServiceImpl implements UserService { @Override public void test() { System.out.println("目标类实现接口方法......"); } }
-
JDK动态代理
通过代理,对目标类进行增强
package com.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * JDK动态代理 * @author CMK * @date 2020-10-19 19:18 */ public class JDKProxy { /** * 生成一个目标类的代理对象 * @param target 目标对象 * @return Object类型的代理类(可明确指定UserService类型) */ public static Object getProxy(Object target){ return Proxy.newProxyInstance( // 代理(Proxy)的newProxyInstance()方法参数说明 JDKProxy.class.getClassLoader(), // 参数1:目标对象的类加载器 target.getClass().getInterfaces(), // 参数2:目标对象实现的接口 new InvocationHandler() { // 参数3:事件处理程序,用于对目标进行增强 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //proxy:目标对象增强后的代理对象 //method:目标对象的方法 //args:目标对象的方法参数 System.out.println("JDK动态代理:执行目标类方法前,此处就可以写代理对象的方法逻辑"); Object result = method.invoke(target,args); //执行目标方法(涉及到反射) System.out.println("JDK动态代理:执行目标类方法后,此处也可以写代理对象的方法逻辑"); return result; } }); } }
-
运行测试类
package com.proxy; import com.proxy.service.UserService; import com.proxy.service.impl.UserServiceImpl; /** * 运行测试类 * @author CMK * @date 2020-10-19 16:46 */ public class Test { public static void main(String[] args) { UserService jdkProxy = (UserService) JDKProxy.getProxy(new UserServiceImpl()); //因为在getUserServiceProxy那里返回的是Object类型,所以此处需要进行强转才可调用下面的test() jdkProxy.test(); } }
-
运行结果
2.5动态代理——Cglib
目标对象没有接口时,JDK动态代理无法使用,此时需要使用Cglib动态代理。
Cglib动态代理:在运行时期动态生成一个类的子类方式实现对目标对象的功能拓展。
-
pom.xml
Cglib动态代理需要引入cglib包
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.1</version> </dependency>
-
基类
package com.proxy.service; /** * @author CMK * @date 2020-10-19 20:02 */ public class UserServiceImpl { public void test(){ System.out.println("目标类方法......"); } }
-
Cglib动态代理
package com.proxy; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * Cglib动态代理 * * @author CMK * @date 2020-10-19 20:03 */ public class CglibProxy { public static Object getProxy(Object target) { return Enhancer.create( //增强者(Enhancer)的create()方法参数说明 target.getClass(), //参数1:设置目标对象的类 new MethodInterceptor() { //参数2:拦截目标对象的方法,进行增强 @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { //o:目标对象增强后的代理对象,也是目标对象的子类 //method:目标对象的方法 //objects:目标对象的方法参数 System.out.println("Cglib动态代理:执行目标类方法前,此处就可以写代理对象的方法逻辑"); Object result = method.invoke(target, objects); //执行目标方法(涉及到反射) System.out.println("Cglib动态代理:执行目标类方法后,此处也可以写代理对象的方法逻辑"); return result; } }); } }
-
测试运行类
package com.proxy; import com.proxy.service.UserServiceImpl; /** * 运行测试类 * @author CMK * @date 2020-10-19 16:46 */ public class Test { public static void main(String[] args) { UserServiceImpl cglibProxy = (UserServiceImpl) CglibProxy.getProxy(new UserServiceImpl()); cglibProxy.test(); } }
-
运行结果
上一篇: 白领周一恐惧症 自我放松最重要
下一篇: 女人心态要放正 美貌不是万能的
推荐阅读
-
利用Nginx反向代理功能解决WEB网站80端口被封的解决方法
-
nginx 作为反向代理实现负载均衡的例子
-
linux下通过Squid反向代理搭建CDN缓存服务器的配置方法
-
在Nginx服务器上配置Google反向代理的基本方法
-
Nginx中的用户认证配置及阻止用户使用代理访问的方法
-
Docker网络代理设置详解
-
php中通过虚代理实现延迟加载的实现代码
-
Apache虚拟目录配置及vue-cli反向代理的设置方法
-
nodejs中request库使用HTTPS代理-踩坑者日常-SegmentFault思否
-
Mybaits 源码解析 (十一)----- 设计模式精妙使用:静态代理和动态代理结合使用:@MapperScan将Mapper接口生成代理注入到Spring