小编给大家分享一下java中代理模式的面试题有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!
静态代理角色分析:
抽象角色 :一般使用接口或者抽象类来实现。
真实角色 :被代理的角色。
代理角色: 代理真实角色 , 代理真实角色后 ,一般会做一些附属的操作。
调用方:使用代理角色来进行一些操作。
我们以租客租客租房子为例,涉及到的对象有:租客、中介、房东。(房东即为被代理对象,中介即为代理对象)
租客通过中介之手租住房东的房子,代理对象中介需要寻找租客租房,并从中获取中介费用。
代码实现:
Rent.java
即抽象角色
// 抽象角色:租房 public interface Rent { public void rent(); }
Host.java
即真实角色
// 真实角色: 房东,房东要出租房子 public class Host implements Rent{ public void rent() { System.out.println("房屋出租"); } }
Proxy.java
即代理角色
//代理角色:中介 public class Proxy implements Rent { private Host host; public Proxy() { } public Proxy(Host host) { this.host = host; } // 租房 public void rent(){ seeHouse(); host.rent(); fare(); } // 看房 public void seeHouse(){ System.out.println("带房客看房"); } // 收中介费 public void fare(){ System.out.println("收中介费"); } }
Client.java
调用方,即客户
// 客户类,一般客户都会去找代理! public class Client { public static void main(String[] args) { // 房东要租房 Host host = new Host(); // 中介帮助房东 Proxy proxy = new Proxy(host); // 你去找中介! proxy.rent(); } }
静态代理的缺点:
需要手动创建代理类,如果需要代理的对象多了,那么代理类也越来越多。
为了解决,这个问题,就有了动态代理 !
说到动态代理,面试的时候肯定会问动态代理的两种实现方式:
先来看公共的 UserService
接口,和 UserServiceImpl
实现类:
/** * @author csp * @date 2021-06-03 */ public interface UserService { /** * 登录 */ void login(); /** * 登出 */ void logout(); }
/** * @author csp * @date 2021-06-03 */ public class UserServiceImpl implements UserService{ @Override public void login() { System.out.println("用户登录..."); } @Override public void logout() { System.out.println("用户推出登录..."); } }
代码如下:
/** * @author csp * @date 2021-06-03 */ public class JDKProxyFactory implements InvocationHandler { // 目标对象(被代理对象) private Object target; public JDKProxyFactory(Object target) { super(); this.target = target; } /** * 创建代理对象 * * @return */ public Object createProxy() { // 1.得到目标对象的类加载器 ClassLoader classLoader = target.getClass().getClassLoader(); // 2.得到目标对象的实现接口 Class<?>[] interfaces = target.getClass().getInterfaces(); // 3.第三个参数需要一个实现invocationHandler接口的对象 Object newProxyInstance = Proxy.newProxyInstance(classLoader, interfaces, this); return newProxyInstance; } /** * 真正执行代理增强的方法 * * @param proxy 代理对象.一般不使用 * @param method 需要增强的方法 * @param args 方法中的参数 * @return */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("JDK 动态代理:登录/登出前逻辑校验......"); Object invoke = method.invoke(target, args); System.out.println("JDK 动态代理:登录/登出后日志打印......"); return invoke; } public static void main(String[] args) { // 1.创建对象 UserServiceImpl userService = new UserServiceImpl(); // 2.创建代理对象 JDKProxyFactory jdkProxyFactory = new JDKProxyFactory(userService); // 3.调用代理对象的增强方法,得到增强后的对象 UserService userServiceProxy = (UserService) jdkProxyFactory.createProxy(); userServiceProxy.login(); System.out.println("=================================="); userServiceProxy.logout(); } }
输出结果如下:
JDK 动态代理:登录/登出前逻辑校验......
用户登录...
JDK 动态代理:登录/登出后日志打印......
==================================
JDK 动态代理:登录/登出前逻辑校验......
用户推出登录...
JDK 动态代理:登录/登出后日志打印......
代码如下:
/** * @author csp * @date 2021-06-03 */ public class CglibProxyFactory implements MethodInterceptor { // 目标对象(被代理对象) private Object target; // 使用构造方法传递目标对象 public CglibProxyFactory(Object target) { super(); this.target = target; } /** * 创建代理对象 * * @return */ public Object createProxy() { // 1.创建Enhancer Enhancer enhancer = new Enhancer(); // 2.传递目标对象的class enhancer.setSuperclass(target.getClass()); // 3.设置回调操作 enhancer.setCallback(this); return enhancer.create(); } /** * 真正执行代理增强的方法 * @param o 代理对象 * @param method 要增强的方法 * @param objects 要增强方法的参数 * @param methodProxy 要增强的方法的代理 * @return * @throws Throwable */ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("cglib 动态代理:登录/登出前逻辑校验......"); Object invoke = method.invoke(target, objects); System.out.println("cglib 动态代理:登录/登出后日志打印......"); return invoke; } public static void main(String[] args) { // 1.创建对象 UserServiceImpl userService = new UserServiceImpl(); // 2.创建代理对象 CglibProxyFactory cglibProxyFactory = new CglibProxyFactory(userService); // 3.调用代理对象的增强方法,得到增强后的对象 UserService userServiceProxy = (UserService) cglibProxyFactory.createProxy(); userServiceProxy.login(); System.out.println("=================================="); userServiceProxy.logout(); } }
测试结果如下:
cglib 动态代理:登录/登出前逻辑校验......
用户登录...
cglib 动态代理:登录/登出后日志打印......
==================================
cglib 动态代理:登录/登出前逻辑校验......
用户推出登录...
cglib 动态代理:登录/登出后日志打印......
① JDK 动态代理本质上是实现了被代理对象的接口,而 CGLib 本质上是继承了被代理对象,覆盖其中的方法。
② JDK 动态代理只能对实现了接口的类生成代理,CGLib 则没有这个限制。但是 CGLib 因为使用继承实现,所以 CGLib 所以无法对 final
类、private
方法和 static
方法进行代理。
③ JDK 动态代理是 JDK 里自带的,CGLib 动态代理需要引入第三方的 jar
包。
④ 在调用代理方法上,JDK动态代理是通过反射机制调用,CGLib 是通过 FastClass 机制直接调用。(看过一篇文章,介绍说 FastClass 简单的理解,就是使用一个 index 下标作为入参,可以直接定位到要调用的方法直接,并进行调用)
在性能上,JDK1.7 之前,由于使用了 FastClass 机制,CGLib 在执行效率上比 JDK 快,但是随着 JDK 动态代理的不断优化,从 JDK 1.7 开始,JDK 动态代理已经明显比 CGLib 更快了。
根本原因是通过 JDK 动态代理生成的类已经继承了 Proxy 类,所以无法再使用继承的方式去对类实现代理。
以上是“java中代理模式的面试题有哪些”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。