-
什么是代理模式?
有很多事情不得不做,但是又不想自己做,我们就可以把自己的信息交给别人,让别人去做,这个就是代理模式。比如你是一个明星,要在杭州举行一场演唱会,是不是有找场地,发通知告诉粉丝等等很多事情要做?但是这些事情不能由你自己做吧,那不是累死了。再比如说我要抢火车票,总不能自己一直在12306刷有没有票吧?这个时候我们就可以把自己的信息提供给抢票软件,然后让抢票软件帮我们刷票。代理模式除了是一种设计模式之外,它更是一种思维,一种好的设计模式甚至是架构,都能在不改变原有形态的基础上扩展出新的功能。
案例:比如我们有一个保存的方法,我们需要保存用户之前需要开启事务,在保存之后需要提交事务,总不能在每个方法都手动加事务吧,这个时候我们就可以用代理模式来实现。
-
Java中实现代理的三种方式:
1 静态代理
静态代理需要被代理的对象和代理对象实现同一个接口,并且代理对象要持有被代理对象的信息。代码如下:
//1.接口
public interface IPersonDao {
void save();
}
//2.被代理对象
public class PersonDao implements IPersonDao{
@Override
public void save() {
System.out.println("保存用户");
}
}
//3.自定义的代理对象,实现和被代理对象相同的接口
public class PersonProxyDao implements IPersonDao {
IPersonDao target;
public PersonProxyDao (IPersonDao target){
this.target = target;
}
@Override
public void save() {
System.out.println("开启事务");
target.save();
System.out.println("提交事务");
}
}
这样就实现了我们的需求,但是这种静态代理的缺点也是很明显的,两个对象要实现同一个接口,如果接口改变了,两个对象都需要改变。并且一个代理对象只能帮助同一类的目标对象,这样的话就会产生很多代理对象,如何解决这个问题呢?我们可以使用动态代理。
动态代理有两种,一种是jdk自带的动态代理,一种是spring提供的cglib代理。
2.jdk自带的动态代理。
//接口
public interface IPersonDao {
void save();
}
//实现类
public class PersonDao implements IPersonDao{
@Override
public void save() {
System.out.println("保存用户");
}
}
//代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyFactory {
//维护一个目标对象
private Object target;
public ProxyFactory(Object target){
this.target=target;
}
//动态给目标对象生成代理对象
public Object getProxyInstance(){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),//参数1:指定当前目标对象的使用的类加载器,方法固定的
target.getClass().getInterfaces(),//参数2: 目标对象实现的接口的类型,使用泛型方式确认类型
new InvocationHandler() {//参数3:自定义Handle,把我们自定义的逻辑处理写在这里
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开启事务");
//执行目标对象方法
Object returnValue = method.invoke(target, args);
System.out.println("提交事务");
return returnValue;
}
}
);
}
}
//测试类
public class AppTest {
public static void main(String[] args) {
IPersonDao target = new PersonDao();
System.out.println(target.getClass());
//给目标对象创建代理对象
IPersonDao proxy = (IPersonDao)new ProxyFactory(target).getProxyInstance();
System.out.println(proxy.getClass());
//执行方法
proxy.save();
}
}
其实就是在运行时重新生成了一个代理类,和被代理的对象实现了同一个接口,然后通过这个代理类去调用方法。 这里被代理类一定要实现接口。下一篇jdk动态原理分析会讲到为什么要这么做。
3.spring的cglib代理
上面的静态代理和动态代理模式都是要求目标对象是实现一个接口的目标对象,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理
//被代理对象
public class PersonDao {
public void save(){
System.out.println("保存数据");
}
}
//代理对象
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class ProxyFactory implements MethodInterceptor {
//维护目标对象
private Object target;
public ProxyFactory(Object target){
this.target = target;
}
//给目标对象创建代理对象
public Object getProxyInstance(){
//1.工具类
Enhancer en = new Enhancer();
//2.设置父类
en.setSuperclass(target.getClass());
//3.设置回调函数
en.setCallback(this);
//返回创建的子类
return en.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("开启事务");
Object returnValue = method.invoke(target,args);
System.out.println("提交事务");
return returnValue;
}
}
//测试方法
public class AppTest {
public static void main(String[] args) {
PersonDao person = new PersonDao();
ProxyFactory proxyFactory = new ProxyFactory(person);
PersonDao proxy = (PersonDao)proxyFactory.getProxyInstance();
System.out.println(proxy.getClass());
proxy.save();
}
}
其原理是生成了一个被代理对象的子类。这种方法不需要被代理对象实现接口,即可完成代理。
ps:这里强烈推荐两篇码农翻身的两篇关于动态代理的文章,把技术写成了故事,非常有趣,易懂。