静态代理角色分析:
我们以租客租客租房子为例,涉及到的对象有:租客、中介、房东。(房东即为被代理对象,中介即为代理对象)
租客通过中介之手租住房东的房子,代理对象中介需要寻找租客租房,并从中获取中介费用。
代码实现:
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动态代理区别?
final
类、private
方法和 static
方法进行代理。jar
包。在性能上,JDK1.7 之前,由于使用了 FastClass 机制,CGLib 在执行效率上比 JDK 快,但是随着 JDK 动态代理的不断优化,从 JDK 1.7 开始,JDK 动态代理已经明显比 CGLib 更快了。
面试题一:JDK 动态代理为什么只能对实现了接口的类生成代理?
根本原因是通过 JDK 动态代理生成的类已经继承了 Proxy 类,所以无法再使用继承的方式去对类实现代理。
总结的面试题也挺费时间的,文章会不定时更新,有时候一天多更新几篇,如果帮助您复习巩固了知识点,还请三连支持一下,后续会亿点点的更新!
为了帮助更多小白从零进阶 Java 工程师,从CSDN官方那边搞来了一套 《Java 工程师学习成长知识图谱》,尺寸 870mm x 560mm
,展开后有一张办公桌大小,也可以折叠成一本书的尺寸,有兴趣的小伙伴可以了解一下,当然,不管怎样博主的文章一直都是免费的~