代理模式详解
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
代理模式详解
代理模式为对象提供⼀个代理以控制对这个对象的访问。
所谓代理,是指与代理元(即:被代理的对象)具有相同接⼝的类,客户端必须通过代理与代理元进⾏交互。
我们可以将代理理解成另⼀个对象的代表。
代理(proxy)模式本质上就是通过⼀个代理对象访问⽬标对象,⽽不直接访问⽬标对象;代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进⾏⼀些功能的附加与增强。
这么做的好处是,可以让⽬标对象只关注业务逻辑,⽽⾮业务逻辑(⽐如⽇志输出等)可以在代理对象中实现,实现业务分离。
代理模式要点:
代理模式包含三个要素:1)接⼝/Interface; 2)代理元/Target:即被代理的对象; 3)代理类/Proxy:代理元的代表,对外提供访问;
代理元与代理类都是接⼝的实现类;
客户端只能访问代理类,⽆法直接访问代理元;
代理分为静态代理和动态代理。
静态代理
静态代理就是在编译时⽣成代理类。
即:通过编码⼿动创建代理类,并在代理类中调⽤代理元。
编码实现
1.接⼝
package effectiveJava.proxy;
public interface HelloService {
void sayHello();
}
2,代理元
package effectiveJava.proxy;
public class HelloServiceImpl implements HelloService{
@Override
public void sayHello() {
System.out.println("Hello Proxy.");
}
}
3,代理类
package effectiveJava.proxy.staticProxy;
import effectiveJava.proxy.HelloService;
public class LogProxy implements HelloService {
private HelloService service;
public LogProxy(HelloService service) {
this.service = service;
}
@Override
public void sayHello() {
System.out.println("Static Proxy : Before Hello....");
service.sayHello();
System.out.println("Static Proxy : After Hello....");
}
}
4,测试类
package effectiveJava.proxy.staticProxy;
import effectiveJava.proxy.HelloServiceImpl;
public class LogProxyDemo {
public static void main(String[] args) {
LogProxy logProxy = new LogProxy(new HelloServiceImpl());
logProxy.sayHello();
}
}
5,测试结果
Static Proxy : Before Hello....
Hello Proxy.
Static Proxy : After Hello....
动态代理
动态代理地实现有两种⽅式:1)基于JDK的动态代理;2)基于CGLIB的动态代理;1)基于JDK的动态代理
API
public class Proxy implements java.io.Serializable {
/**
* 创建代理实例
* @param loader 代理元的类加载器
* @param interfaces 代理元的接⼝
* h ⼀个 InvocationHandler 对象
*/
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h); }
/**
*
* 每个代理的实例都有⼀个与之关联的 InvocationHandler 实现类,
* 如果代理的⽅法被调⽤,那么代理便会通知和转发给内部的 InvocationHandler 实现类,由它决定处理。
*/
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
编码实现
1,接⼝、代理元(编码与静态代理⼀致,不再赘述)
2,代理类(必须实现InvocationHandler接⼝)
package effectiveJava.proxy.v0;
import ng.reflect.InvocationHandler;
import ng.reflect.Method;
public class HelloInvocation implements InvocationHandler {
/**
* 代理元
*/
private Object target;
public HelloInvocation(Object target) {
this.target = target;
}
/**
*
* @param proxy 代理类实例
* @param method 实际要调⽤的⽅法
* @param args 实际要调⽤⽅法的参数类型
* @return结果值
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("HelloInvocation : Before Hello....");
Object reslut = method.invoke(target, args);
System.out.println("HelloInvocation : After Hello....");
return reslut;
}
}
3,测试类
package effectiveJava.proxy.v0;
import effectiveJava.proxy.HelloService;
import effectiveJava.proxy.HelloServiceImpl;
import ng.reflect.Proxy;
/**
* 通过Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)创建代理对象的实例
*/
public class HelloInvocationDemo {
public static void main(String[] args) {
HelloServiceImpl helloService = new HelloServiceImpl();
HelloInvocation helloInvocation = new HelloInvocation(helloService);
HelloService impl = (HelloService)Proxy.newProxyInstance(
helloService.getClass().getClassLoader(),
helloService.getClass().getInterfaces(),
helloInvocation);
impl.sayHello();
}
}
4,测试结果
HelloInvocation : Before Hello....
Hello Proxy.
HelloInvocation : After Hello....
2)基于CGLIB的动态代理
Cglib是基于继承的⽅式进⾏代理,代理类去继承⽬标类,每次调⽤代理类的⽅法都会被⽅法拦截器拦截,在拦截器中才是调⽤⽬标类的该⽅法的逻辑。
因此,基于CGLIB的动态代理不需要接⼝。
编码实现
1,引⼊架包
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
2,代理类(HelloServiceImpl.java,编码与静态代理⼀致)
3,⽅法拦截器
package effectiveJava.proxy.cglib;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import ng.reflect.Method;
public class LogInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("Cglib : Before hello...");
//调⽤⽗委⽅法
Object result = methodProxy.invokeSuper(object, args);
System.out.println("Cglib : After hello...");
return result;
}
}
4,测试类
package effectiveJava.proxy.cglib;
import effectiveJava.proxy.HelloService;
import effectiveJava.proxy.HelloServiceImpl;
import net.sf.cglib.proxy.Enhancer;
public class CglibDemo {
public static void main(String[] args) {
//创建Enhancer对象,类似于JDK动态代理的Proxy类
Enhancer enhancer = new Enhancer();
//设置⽗类
enhancer.setSuperclass(HelloServiceImpl.class);
//设置回调函数(拦截器)
enhancer.setCallback(new LogInterceptor());
//创建代理类实例
HelloService service = (HelloService)enhancer.create();
service.sayHello();
}
}
5,测试结果
Cglib : Before hello...
Hello Proxy.
Cglib : After hello...
总结:
静态代理是在编译时创建代理,动态代理是在运⾏时创建代理;
JDK动态代理是基于接⼝的⽅式,CGLib动态代理是基于继承;相关完成版代码,请查看。