JDK代理
–基于接口的代理
代理类和委托类要实现相同的接口,因为代理真正调用的还是委托类的方法。
1.JDK静态代理
创建实体类
public class User {
private int uid;
private String uname;
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
}
– 第一步:创建 UserService 接口
public interface UserService {
// 添加 user
public void addUser(User user);
// 删除 user
public void deleteUser(int uid);
}
– 第二步:创建 UserService的实现类
public class UserServiceImpl implements UserService {
public void addUser(User user) {
System.out.println("增加 User");
}
public void deleteUser(int uid) {
System.out.println("删除 User");
}
}
– 第三步:创建事务类
public class MyTransaction {
// 开启事务
public void before() {
System.out.println("开启事务");
}
// 提交事务
public void after() {
System.out.println("提交事务");
}
}
– 第四步:创建代理类 ProxyUser.java
public class ProxyUser implements UserService {
// 真实类
private UserService userService;
// 事务类
private MyTransaction transaction;
// 使用构造函数实例化
public ProxyUser(UserService userService, MyTransaction transaction) {
this.userService = userService;
this.transaction = transaction;
}
public void addUser(User user) {
transaction.before();
userService.addUser(user);
transaction.after();
}
public void deleteUser(int uid) {
transaction.before();
userService.deleteUser(uid);
transaction.after();
}
}
–测试
public class TestUser {
@Test
public void testOne() {
MyTransaction transaction = new MyTransaction();
UserService userService = new UserServiceImpl();
// 产生静态代理对象
ProxyUser proxy = new ProxyUser(userService, transaction);
proxy.addUser(null);
proxy.deleteUser(0);
}
}
这是一个很基础的静态代理,业务类UserServiceImpl 只需要关注业务逻辑本身,保证了业务的重用性,这也是代理类的优点,没什么好说的。我们主要说说这样写的缺点:
①、代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。
②、如果接口增加一个方法,比如 UserService 增加修改 updateUser()方法,则除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
2.JDK动态代理
动态代理就不要自己手动生成代理类了,我们去掉 ProxyUser.java 类,增加一个 ObjectInterceptor.java 类
public class ObjectInterceptor implements InvocationHandler {
// 目标类
private Object target;
// 切面类(这里指事务类)
private MyTransaction transaction;
// 通过构造器赋值
public ObjectInterceptor(Object target, MyTransaction transaction) {
this.target = target;
this.transaction = transaction;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 开启事务
this.transaction.before();
// 调用目标类方法
method.invoke(this.target, args);
// 提交事务
this.transaction.after();
return null;
}
}
–测试
public class TestUser2 {
@Test
public void testOne() {
// 目标类
Object target = new UserServiceImpl();
// 事务类
MyTransaction transaction = new MyTransaction();
ObjectInterceptor proxyObject = new ObjectInterceptor(target, transaction);
/**
* 三个参数的含义: 1、目标类的类加载器 2、目标类所有实现的接口 3、拦截器
*/
UserService userService = (UserService) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), proxyObject);
userService.addUser(null);
userService.deleteUser(11);
}
}
那么使用动态代理来完成这个需求就很好了,后期在 UserService 中增加业务方法,都不用更改代码就能自动给我们生成代理对象。而且将 UserService 换成别的类也是可以的。
也就是做到了代理对象能够代理多个目标类,多个目标方法。
不管是哪种方式实现动态代理。本章的主角:AOP 实现原理也是动态代理
JDK代理限制:目标类需要实现一个接口!!!
CGLib代理
使用JDK创建代理有一个限制,它只能为接口创建代理实例.这一点可以从Proxy的接口方法 newProxyInstance(ClassLoader loader,Class [] interfaces,InvocarionHandler h)中看的很清楚
第二个入参 interfaces就是需要代理实例实现的接口列表.
对于没有通过接口定义业务方法的类,如何动态创建代理实例呢? JDK动态代理技术显然已经黔驴技穷,CGLib作为一个替代者,填补了这一空缺.
GCLib采用底层的字节码技术,可以为一个类创建子类,在子类中采用方法拦截的技术拦截所有父类方法的调用并顺势志入横切逻辑.
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
创建代理器
public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
// 切面类(这里指事务类)
private MyTransaction transaction;
public CglibProxy(MyTransaction transaction) {
this.transaction=transaction;
}
// 设置被代理对象
public Object getProxy(Class clazz) {
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
transaction.before();
Object invoke = methodProxy.invokeSuper(obj, objects);
transaction.after();
return invoke;
}
}
–测试
@Test
public void testOne() {
// 事务类
MyTransaction transaction = new MyTransaction();
CglibProxy cglibProxy = new CglibProxy(transaction);
UserServiceImpl userService = (UserServiceImpl) cglibProxy.getProxy(UserServiceImpl.class);
userService.addUser(null);
userService.deleteUser(11);
}