小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
静态代理和动态代理的区别
- 静态代理需要自己去实现代理类
- 动态代理直接使用代理类(JDK、CGlib)
静态代理就是上面结构性模式——代理模式中的代码的体现
动态代理
使用动态代理的原因
- 使用代理的原因
- 动态代理相对于静态代理不需要有各种冗余的类编写
jdk动态代理
整体的实现基于以下几点:
- JDK自带的
java.lang.reflect.Proxy - 反射机制
- 固定规则
InvocationHandler
逻辑实现
- 创建基础接口
Linux - 创建真是的目标类
ServerLinux - 创建动态代理类
JdkProxy,在代理类中实现代理的强化逻辑,并在最后调用目标类进行执行 - 使用反射机制生成代理对象来进行操作
代码实现
1、2与静态代理一致
- 实现JdkProxy
/**
* @ClassName JdkProxy
* @Desc jdk动态代理
* @Author YangMingYu
* @Date 2021/10/26 4:19 下午
* @Version 1.0
**/
/**
* 1. 实现InvocationHandler接口,及其方法
* 2. 传入目标类(这里的目标类可以是继承的模式来生成的逻辑)
* 3. 在invoke中进行代理增强逻辑处理
*/
public class JdkProxy implements InvocationHandler {
Linux tarjet;
public JdkProxy(Linux tarjet) {
this.tarjet = tarjet;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//处理身份验证
//调用服务器
String username = String.valueOf(args[0]);
String password = String.valueOf(args[1]);
if (checkAuth(username, password)) {
Object invoke = method.invoke(tarjet, "root", "123456");
return invoke;
} else {
//处理异常
return "跳板机验证失败";
}
//进行一些处理结果的操作
}
public Boolean checkAuth(String name, String password) {
if ("张三".equals(name) && "123".equals(password)) {
return true;
}
return false;
}
public static void main(String[] args) {
ServerLinux serverLinux = new ServerLinux();
JdkProxy jdkProxy = new JdkProxy(serverLinux);
Linux linux = (Linux) Proxy.newProxyInstance(jdkProxy.getClass().getClassLoader(), serverLinux.getClass().getInterfaces(), jdkProxy);
linux.play("张三", "123");
}
}
CGLIB动态代理
-
导入两个包
cglib(动态代理)和asm(操作字节码.class文件) -
实现代理逻辑
/**
* @ClassName CglibProxy
* @Desc CglibProxy
* @Author YangMingYu
* @Date 2021/10/26 4:51 下午
* @Version 1.0
**/
/**
* 1. 倒入cglib和asm包
* 2. 创建代理类继承MethodInterceptor
* 3。 实现其中的方法并实现代理的增强业务逻辑
* 4。 使用Enhancer对象来创建代理类
*/
public class CglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
String username = String.valueOf(objects[0]);
String password = String.valueOf(objects[1]);
if (checkAuth(username, password)) {
//Master
String[] strings = new String[]{"root", "123456"};
Object invokeSuper = methodProxy.invokeSuper(o, strings);
return invokeSuper;
} else {
//处理异常
return "跳板机验证失败";
}
}
public Boolean checkAuth(String name, String password) {
if ("张三".equals(name) && "123".equals(password)) {
return true;
}
return false;
}
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(ServerLinux.class);
enhancer.setCallback(new CglibProxy());
Linux linux = (Linux) enhancer.create();
linux.play("张三", "123");
}
}
cglib与jdk实现动态代理的区别以及一些问题
- jdk使用Java内部的反射机制实现
- cglib使用asm来加载并操作字节码生成子类实现
- jdk代理必须统一接口(实现同一个接口)
如果目标对象实现了接口,默认使用jdk来实现
cglib的效率要比jdk高
Spring会根据目标类是否实现接口来判断使用哪个代理方式
SpringAop中有前置通知、后置通知
主要用来“打印日志”,“权限控制”,“控制层进行线程全局日志的监控”