设计模式9 代理模式

定义

为另一个对象提供一个替身或占位符以控制对这个对象的访问。

代理模式可以分为静态代理动态代理

  • 静态代理:由程序员创建或特定工具自动生成源代码,在对其编译。在程序员运行之前,代理类.class文件就已经被创建了
  • 动态代理:在程序运行时通过反射机制动态创建

主要角色

在这里插入图片描述
图源:07 代理模式:帮我拿一下快递

  • Subject 抽象主题:声明了目标对象和代理对象的共同接口
  • RealSubject 具体主题:也叫做被委托角色、被代理角色。是业务逻辑的具体执行者。
  • Proxy 代理主题角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。

静态代理

Subject 抽象主题:

/**
* 学生服务接口
* 提供学生查询功能
*/
public interface StudentService {
    String getStudentById(long id);
}

RealSubject 具体主题,即实际登录逻辑

/**

*/
public class StudentServiceImpl implements StudentService{
	// 查询用户名
	Map<long,String> map = new HashMap<>();
    @Override
    public String getStudentById(long id) {
        return map.get(id);
    }
}

Proxy 代理主题,操作目标对象

public class StudentServiceProxy implements StudentService{

    private StudentService studentService;

    public StudentServiceProxy(StudentService studentService) {
        this.studentService = studentService;
    }

    @Override
    public void userLogin() {
        System.out.println("查询前业务逻辑...");
        studentService.getStudentById();
        System.out.println("查询后业务逻辑...");
    }
}

可以看出,这个代理是由程序员手动指定创建的,灵活性较差,可以使用动态代理来进行调用。
在使用代理时u,可以直接:

public class Client {
    public static void main(String[] args) {
    	StudentService studentService = new StudentServiceImpl();
		StudentServiceProxy studentServiceProxy = new StudentServiceProxy(studentService);
		studentServiceProxy.getStudentById(1L);
	}
}

动态代理

JDK的Proxy

JDK自带的动态代理InvocationHandler位于JDK反射包下,其作用是在实现JDK动态代理的时候提供了动态执行增强逻辑的方法。

public class DynamicProxyHandler implements InvocationHandler {

    private Object object;

    public DynamicProxyHandler(Object object) {
        this.object = object;
    }
	
	/**
	 *
	 * @param proxy 代理对象
	 * @param method 目标对象方法
	 * @param args 目标对象参数
	 * @return
	 * @throws Throwable
	 */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("查询前业务逻辑...");
        Object result = method.invoke(object, args);
        System.out.println("查询后业务逻辑...");
        return result;
    }
}

在调用的时候:

public class Client {
    public static void main(String[] args) {
    	StudentService studentService = new StudentServiceImpl();
    	StudentService dynamicProxy = (StudentService) Proxy.newProxyInstance(StudentService.class.getClassLoader(), new Class[]{StudentService.class}, new DynamicProxyHandler(studentService));
        dynamicProxy.getStudentById(1L);
	}
}

这样,InvocationHandler实现了无侵入式的增加被代理类的功能,Proxy.newProxyInstance利用传入参数,运行时动态生成被代理类的实际对象。
用到了Proxy.newProxyInstance()函数,官方文档其参数为:

/**
* 
* loader - the class loader to define the proxy class
* interfaces - the list of interfaces for the proxy class to implement
* h - the invocation handler to dispatch method invocations to
* @return 
* a proxy instance with the specified invocation handler of a 
* proxy class that is defined by the specified class loader 
* and that implements the specified interfaces
* 具有代理类的指定调用处理程序的代理实例,该代理类由指定的类装入器定义并实现指定的接口
*/
public static Object newProxyInstance(ClassLoader loader,
                      Class<?>[] interfaces,
                      InvocationHandler h)
                               throws IllegalArgumentException

Cglib代理

public class CglibProxy implements MethodInterceptor {

    private Object target;

    public Object getInstance(final Object target){
        this.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("查询前业务逻辑...");
        Object result = methodProxy.invokeSuper(object, args);
        System.out.println("查询后业务逻辑...");
        return result;
    }
}

调用的时候:

public class Client {
    public static void main(String[] args) {
    	StudentService studentService = new StudentServiceImpl();
    	CglibProxy cglibProxy = new CglibProxy();
        StudentServiceImpl instance = (StudentServiceImpl) cglibProxy.getInstance(studentService);
        instance.getStudentById(1L);
	}
}

优缺点

JDK自带的Proxy优点:

  • InvocationHandler接口的实现类可以复用
  • 可以在不修改原来代码的基础上,就在原来代码的基础上做操作,即AOP,面向切面编程

缺点:

  • 只能针对接口生成代理,不能只针对某一个类生成代理

使用Cglib代理,创建代理对象时所花费的时间却比JDK多得多,但是Cglib创建的动态代理对象比JDK创建的动态代理对象的性能更高

参考

《Head First 设计模式》(十三):代理模式
07 代理模式:帮我拿一下快递
官方文档 java.lang.reflect-Class Proxy
Java动态代理之InvocationHandler最简单的入门教程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值