前言
代理是一种常用的设计模式,它为其他对象提供一种代理以控制对这个对象的访问。通俗来讲就是我们通过代理类来调用委托类的方法,并且我们可以在代理类中加入新的功能。它们之间的关系如下:
静态代理
创建一个接口,用来约束委托类和代理类的方法。
public interface House {
public void rent();
}
创建一个委托类(房东)
//委托类
public class Landlord implements House{
@Override
public void rent() {
System.out.println("出租一间房子");
}
}
创建一个代理类(中介)
//代理类
public class Intermediary implements House {
House landlord;
public Intermediary(House landlord) {
this.landlord = landlord;
}
@Override
//代理方法
public void rent() {
// 调用委托类的方法并加上新的功能
System.out.println("看房");
landlord.rent();
}
}
代理类引用了委托类,并且调用委托类的方法上可以增加新的功能。
测试
@Test
public void testStatic(){
House landlord = new Landlord();
House intermediary = new Intermediary(landlord);
intermediary.rent();
}
静态代理的缺点很明显,如果委托类很多并且委托类有很多方法的话,我们都需要手动的为每一个类每一个方法创建代理,是十分麻烦的,由此引出动态代理,可以很好地解决静态代理的弊端。
动态代理
动态代理介绍
动态代理添加了一个中间处理类,当我们调用委托类的方法是,会进入中间处理类,我们可以将新添加的功能放在中间处理类。中间处理类可以对代理类中的函数进行统一管理,而不用像静态代理一样修改所有的代理方法。
动态代理主要有两种
- jdk动态代理 :委托类必须实现接口
- cglib动态代理 :通过继承的方式代理委托类,委托类没有接口也可以代理
jdk动态代理
jdk动态代理需要使用InvocationHandler接口和Proxy类的newProxyInstance方法。
创建一个接口
public interface UserService {
public void addUser();
public void deleteUser();
}
创建实现类(委托类)
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("添加用户");
}
@Override
public void deleteUser() {
System.out.println("删除用户");
}
}
创建中间处理类
//实现InvocationHandler接口,成为中间处理类
public class UserServiceProxy implements InvocationHandler {
private UserService service;
public UserService getProxy(UserService service){
this.service = service;
// 该方法返回一个代理对象
// 参数1位为类加载器,参数2为委托类的class类型接口数组,参数3为实现InvocationHandler的实现类
return (UserService)Proxy.newProxyInstance(service.getClass().getClassLoader(),service.getClass().getInterfaces(),this);
}
// InvocationHandler的实现方法,被拦截的方法将在这里被调用
// 参数1为代理对象的实例,参数2为委托类被拦截的方法,参数3为方法的参数数组
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("权限检查...");
Object invoke = method.invoke(service,args);
return invoke;
}
}
newProxyInstance方法会返回一个代理对象。
测试
@Test
public void testJdk(){
// 委托类
UserService service = new UserServiceImpl();
// 中间处理类
UserServiceProxy userServiceProxy = new UserServiceProxy();
// 代理类
UserService serviceProxy = userServiceProxy.getProxy(service);
// 调用代理类方法
serviceProxy.addUser();
serviceProxy.deleteUser();
}
可以看到动态代理可以动态的管理委托类的所有方法。
cglib动态代理
使用cglib需要导入cglib的jar包。
cglib动态代理需要使用MethodInterceptor接口和Enhancer类。
创建委托类
public class Person {
public void eat(){
System.out.println("吃饭");
}
}
创建中间处理类
//实现MethodInterceptor成为处理类
public class PersonProxy implements MethodInterceptor {
public <T> T getProxy(Class<T> clazz){
//创建工具类
Enhancer enhancer = new Enhancer();
//设置委托类为其父类
enhancer.setSuperclass(clazz);
//设置回调函数,即方法被拦截后调用的方法
enhancer.setCallback(this);
//创建Person的代理类并返回
return (T) enhancer.create();
}
//该方法为回调方法,方法被拦截后将会调用
//参数1为代理类对象,参数2为被拦截的委托类的方法,参数3为方法参数列表,参数4为被拦截的方法的代理对象
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("吃饭前要洗手");
//参数1为代理类对象,参数2为方法参数列表
Object invoke = methodProxy.invokeSuper(o,objects);
return invoke;
}
}
测试
@Test
public void testCglib(){
//委托类
Person p = new Person();
//中间处理类
PersonProxy personProxy = new PersonProxy();
//代理类
Person proxy = personProxy.getProxy(p.getClass());
//调用代理类方法
proxy.eat();
}
由于cglib是通过继承来实现代理,所以被final和static修饰的类或方法不能被代理,因为被static和final修饰的方法不能被重写,而被final修饰的类不能被继承,所以也就不能被代理了。