java代理模式

214 阅读3分钟

设计模式-代理模式 

一、什么是代理模式

代理模式是为其他对象提供一种代理以控制对这个对象的访问。这种功能只有在编译无法确定要实现哪个接口时才有必要使用。利用代理可以创建一个实现了一组接口的新类。代理类与被代理类必须实现同一个接口,代理对象是在运行时由调用处理器定义的新类,它有一个名字,如$Proxy0。代理对象一旦被创建,与虚拟机上的任何其他类没有什么区别。 

代理模式本质上是不改变原有功能的基础上,增加新的功能,如日志、权限等,Spring AOP的实现原理就是基于代理模式

二、为什么要用代理模式

  • 中介隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。 

  • 开闭原则:增加功能:代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类。 

三、三种代理模式 

  • 静态代理 
  • jdk动态代理 

1.首先创建服务接口

public class SmsServiceImpl implements SmsService{
    @Override
    public interface SmsService {
         String sendMsg(String msg);
    }
}

2.实现服务接口

public class SmsServiceImpl implements SmsService{
    @Override
    public String sendMsg(String msg) {
        System.out.println("send msg:"+msg);
        return msg;
    }
}

3.创建代理类

public class JdkProxyFactory {

    /**
     * 获取某个类的代理对象
     * @param target
     * @return
     */
    public static Object getProxy(Object target){
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),//目标类加载
                target.getClass().getInterfaces(),//代理需要实现的接口,可指定多个
                // 使用lambda表达式实现,相当于
                /*new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        return null;
                    }
                }*/
                (Object proxy, Method method, Object[] args)->{
                    // before do something...
                    Object result = method.invoke(target, args);
                    // after do something...
                    return result;
                }
        );
    }
}

4.调用代理

public static void main(String[] args) {
        SmsService smsService = (SmsService) JdkProxyFactory.getProxy(new SmsServiceImpl());
        smsService.sendMsg("hello john");
}
  • Cglib代理 

上述例子,我们发现要实现jdk动态代理,必须定义服务接口,在我们实际开发中如果出现被代理类未实现接口,此时我们可以使用cblib动态代理

创建cglib代理类

public class CglibProxyFactory {
  public static Object getProxy(Class<?> classz){
    //创建动态代理增强类    
    Enhancer enhancer =new Enhancer();
    //设置类加载器    
    enhancer.setClassLoader(classz.getClassLoader());    
    //设置被代理类    
    enhancer.setSuperclass(classz);    
    //设置方法拦截器    
    enhancer.setCallback(
            (MethodInterceptor) (o, method, objects, methodProxy) -> {
                        // do something        
                       Object object = methodProxy.invokeSuper(o,objects);
                       // do something 
                       return object;    }); 
   //创建代理类    
   return enhancer.create();
 }}

调用代理

SmsServiceImpl smsService = (SmsServiceImpl)CglibProxyFactory.getProxy(SmsServiceImpl.class);
smsService.sendMsg("hello");