目录
一、静态代理-代理设计模式
1.创建方法接口,目标类和代理类实现这个接口
2. 代理类中包含目标类的成员变量,通过构造函数进行传参
// 传统静态代理
public class UserProxy implements UserService {
private UserService userService;
public UserProxy(UserService userService) {
this.userService = userService;
}
@Override
public User getUserByName(String username, Integer age) {
getCurDate();
User user = userService.getUserByName(username, age);
Commit();
return user;
}
@Override
public int getUserCounts() {
getCurDate();
int count = userService.getUserCounts();
Commit();
return count;
}
// 代理类增强方法
public void getCurDate() {
Date date = new Date();
SimpleDateFormat dft = new SimpleDateFormat("yyyy-MM-dd");
String curDate = dft.format(date);
System.out.println(curDate);
}
public void Commit() {
System.out.println("事务提交");
}
}
问题:代码冗余,增强的功能需要添加在所有需要的方法中,当目标类增多的时候,需要为每个目标类都要创建代理类;否则,使用成员变量的方式也会造成一个类中方法量过多,不易管理
二、JDK动态代理
使用java虚拟机的类加载机制:
- 通过一个类的全限定名来获取定义此类的二进制字节流
- 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
- 在内存中生成一个代表这个类的 java.lang.Class 对象,作为方法区这个类的各种数据访问入口
动态代理分为:JDK动态代理和cglib动态代理,两者分别基于接口实现和类继承实现
jdb动态代理:
1.创建Proxy对象,通过newInstance方法获取代理对象实例;
2.newInstance中的三个参数:目标类的类加载器,接口全限定类,InvocationHandler对象
public class UserDynamicProxy {
private UserService userService;
public UserDynamicProxy(UserService userService) {
this.userService = userService;
}
// 通过动态代理获取代理对象
public Object getObject() {
// jdk动态代理固定参数:目标类加载器,目标接口,InvocationHandler对象
Object proxy = Proxy.newProxyInstance(userService.getClass().getClassLoader(),
new Class[]{UserService.class},
(object, method, args) -> {
// 增强方法
Object res = method.invoke(userService, args);
System.out.println("提交事务");
return res; // 这是个代理对象
}
);
/* InvocationHandler接口方法 public Object invoke(Object proxy, Method method, Object[] args)
* 参数:
* Object proxy:获取的代理对象
* Method method:调用的目标类方法
* Object[] args:方法参数
* */
return proxy;
}
}
测试方法:
@Test
public void testDynamicProxy() {
UserService userService = new UserServiceImpl();
UserDynamicProxy userDynamicProxy = new UserDynamicProxy(userService);
UserService proxy = (UserService) userDynamicProxy.getObject();
User user = proxy.getUserByName("娜美", 18);
System.out.println("dynamic user:" + user);
System.out.println("-----------华丽分割线-------------");
int count = proxy.getUserCounts();
System.out.println("数量:" + count);
}
测试发现,在newInstance中设置一次增强方法,UserService的所有方法都会被添加
三、Cglib动态代理
在maven中使用cglib,需要导入包:
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
</dependency>
package com.righteye;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 使用cglib实现动态代理
*/
public class CglibFactor implements MethodInterceptor {
private Object target;
// 将目标对象作为参数传入
public CglibFactor(Object target) {
this.target = target;
}
/*
创建代理对象
*/
public Object createProxy() {
// 1.创建Enhancer
Enhancer enhancer = new Enhancer();
// 2.将目标对象作为父类
enhancer.setSuperclass(target.getClass());
// 3.设置回调操作
enhancer.setCallback(this);
return enhancer.create();
}
@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) {
UserServiceImpl userService = new UserServiceImpl();
CglibFactor cglibFactor = new CglibFactor(userService);
UserServiceImpl userservice = (UserServiceImpl) cglibFactor.createProxy();
userservice.test();
}
}
jdk动态代理和cglib区别
JDK动态代理:基于Java反射机制实现,必须要实现了接口的业务类才能用这种办法生成代理对象。
cglib动态代理:基于ASM机制实现,通过生成业务类的子类作为代理类。
JDK Proxy 的优势:
- 最小化依赖关系,减少依赖意味着简化开发和维护,JDK 本身的支持,可能比 cglib 更加可靠。
- 平滑进行 JDK 版本升级,而字节码类库通常需要进行更新以保证在新版 Java 上能够使用。
- 代码实现简单。
基于类似 cglib 框架的优势:
- 无需实现接口,达到代理类无侵入
- 只操作我们关心的类,而不必为其他相关类增加工作量。
- 高性能
由于CgLib动态代理本质使用的继承实现,因此无法为private, final, static进行方法增强;
问题:为什么JDK动态代理只能对接口的类生成代理?
JDK动态代理的类已经继承了Proxy类,在Java中不存在多继承,所以无法在使用继承实现
spring中的aop机制就是依靠动态代理进行实现的,统一了cglib和jdk动态代理实现上的差异,给出了统一的规范,简化了学习的困难。
spring: spring复习_右眸Remnant的博客-优快云博客