代理模式概述
在我们的生活中,有很多普通而又可敬的建筑工人,他们自己有技术,却没有机会随便参与一个项目中去;这时候他们往往会去找也是搞建筑的包工头,包工头手上有很多活可以分派给工人去做。
这个过程中包工头就相当于是代理类,主要就是接活;
建筑工人就相当于是被代理类,他们负责实际工作的完成。
被代理类和代理类都要实现一个同样的接口;就像上述例子中包工头和建筑工人都要是搞建筑这一行的,这样就能保证包工头接的活,下面的人都能完成;而下面的人接到的任务一定是建筑相关的,能够保证完成。
静态代理
静态代理代码结构比较简单,需要有三个要素:
- 共同的接口:定义方法不提供实现,供外部调用;
- 实现类:实现上述接口,提供上述方法的具体实现;
- 代理类:注入的是实现类,调用接口的方法实际是调用实现类的方法的实现。
下面看代码实现:
package com.wgs.静态代理;
/**
* 静态代理
* @author GenshenWang.nomico
* @time 2017/05/28
*
*/
public class StaticProxyDemo {
//公共接口,没有任何实现,必须.
static interface CommonService{
public void sayHello();
}
//公共接口的具体实现
static class RealService implements CommonService{
@Override
public void sayHello() {
System.out.println("hello,静态代理!");
}
}
//产生一个代理类,此类必须实现公共接口,作用:具有sayHello功能的类
static class StaticProxy implements CommonService{
private CommonService realService;
//通过构造器注入接口,实际注入接口的是RealService
public StaticProxy(CommonService service){
this.realService = service;
}
//此处模拟的即为AOP编程思想。sayHello()方法实现不变,只需在其上下加上一些诸如日志事务等代码,
//无需在sayHello()中加上与业务代码无关的代码
@Override
public void sayHello() {
System.out.println("模拟日志输出1.....");
realService.sayHello();
System.out.println("模拟日志输出2.....");
}
}
//测试类
public static void main(String[] args) {
CommonService service = new RealService();
CommonService proxy = new StaticProxy(service);
proxy.sayHello();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
输出:
模拟日志输出1.....
hello,静态代理!
模拟日志输出2.....
- 1
- 2
- 3
在上述例子中我们可以看到,在不修改sayHello()方法源码的情况下即可在其上下加上调试语句,这个过程是通过代理类实现的。
为什么叫静态代理呢?
可以看到我们在程序中固定的为CommonServiceA接口和RealServiceA实现类造出了一个代理类StaticProxy。
缺点就是我们如果再想为CommonServiceB类,CommonServiceC类…实现代理类,必须得另建对应代理类,就会显得很麻烦,这时候就需要动态代理去实现它了。
动态代理实现方式
一说到动态代理,我们第一个想到肯定是大名鼎鼎的Spring AOP了。在AOP的源码中用到了两种动态代理来实现拦截切入功能:jdk动态代理和cglib动态代理。两种方法同时存在,各有优劣。jdk动态代理是由java内部的反射机制来实现的,cglib动态代理是通过继承来实现的,底层则是借助asm(Java 字节码操控框架)来实现的(采用字节码的方式,给A类创建一个子类B,子类B使用方法拦截的技术拦截所以父类的方法调用)。总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。还有一点必须注意:jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用。由此可以看出,jdk动态代理有一定的局限性,cglib这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。。
公用的接口和实现类
- public interface UserService {
- public String getName(int id);
- public Integer getAge(int id);
- }
- public class UserServiceImpl implements UserService {
- @Override
- public String getName(int id) {
- System.out.println("------getName------");
- return "Tom";
- }
- @Override
- public Integer getAge(int id) {
- System.out.println("------getAge------");
- return 10;
- }
- }
JDK的动态代理实现
jdk的动态代理,依赖的是反射包下的invocationHandler接口,我们的代理类实现invocationHandler,重写invoke()方法,每当我们的代理类调用方法时,都会默认先经过invoke()方法。
- public class UserInvocationHandler implements InvocationHandler {
- private Object target;
- UserInvocationHandler() {
- super();
- }
- UserInvocationHandler(Object target) {
- super();
- this.target = target;
- }
- @Override
- public Object invoke(Object o, Method method, Object[] args) throws Throwable {
- if("getName".equals(method.getName())){
- System.out.println("++++++before " + method.getName() + "++++++");
- Object result = method.invoke(target, args);
- System.out.println("++++++after " + method.getName() + "++++++");
- return result;
- }else{
- Object result = method.invoke(target, args);
- return result;
- }
- }
- }
测试类
- public class M {
- public static void main(String[] args) {
- UserService userService = new UserServiceImpl();
- InvocationHandler invocationHandler = new UserInvocationHandler(userService);
- UserService userServiceProxy = (UserService) Proxy.newProxyInstance(
- userService.getClass().getClassLoader(),
- userService.getClass().getInterfaces(),
- invocationHandler);
- System.out.println(userServiceProxy.getName(1));
- System.out.println(userServiceProxy.getAge(1));
- }
- }
CGLIB的动态代理实现
- public class CglibMethodInterceptor implements MethodInterceptor {
- @Override
- public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
- System.out.println("------before " + methodProxy.getSuperName() + "------");
- Object o1 = methodProxy.invokeSuper(o, args);
- System.out.println("------after " + methodProxy.getSuperName() + "------");
- return o1;
- }
- }
- public class M {
- public static void main(String[] args) {
- CglibMethodInterceptor cglibProxy = new CglibMethodInterceptor();
- Enhancer enhancer = new Enhancer();
- enhancer.setSuperclass(UserServiceImpl.class);
- enhancer.setCallback(cglibProxy);
- UserService o = (UserService) enhancer.create();
- o.getName(1);
- o.getAge(1);
- }
- }
ps:cglib的动态代理,需要cglib.jar和asm.jar支持