为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。假设某公司的老板需要和某小公司签订一份合同,但老板正好没空,于是便赋予秘书签合同的权利,让秘书代表自己去和这家公司签订合同.
抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
代理模式的实现可以分为静态代理模式和动态代理模式。
① 抽象角色
/**
* 抽象角色
* 签合同
*/
public interface SignContract {
void signContract();
}
② 真实角色
/**
* 真实角色
* 老板
*/
public class Boos implements SignContract{
@Override
public void signContract() {
System.out.println("和***公司签订合同");
}
}
③ 代理角色
/**
* 代理角色
* 秘书
*/
public class Secretray implements SignContract{
private Boos boos;
public Secretray(final Boos boos){
this.boos=boos;
}
@Override
public void signContract() {
System.out.println("签合同前的准备");
boos.signContract();
System.out.println("签合同后的准备");
}
}
④ 测试
class Test{
public static void main(String[] args) {
Boos boos=new Boos();
Secretray secretray=new Secretray(boos);
secretray.signContract();
}
}
缺点:因为代理对象,需要与目标对象实现一样的接口,我们得为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理对象与目标对象都要改变。不利于后期的维护。
优点:可以做到在符合开闭(不修改目标对象的功能)原则的情况下对目标对象进行功能扩展。
设想:我们能不能只编写一个代理类生成器,当我们需要某个类的代理对象时,代理类生成器会帮我
们自动创建对应的代理类。这就是动态代理的实现思路。
动态代理模式:动态代理模式又可以分为 JDK 动态代理和 CGLIB 动态代理。
我们不再需要再手动的创建代理类,我们只需要编写一个动态处理器就可以了。真正的代理对象
由 JDK 在运行时为我们动态的来创建。
① 抽象角色
/**
* 抽象角色
* 签合同
*/
public interface SignContract {
void signContract();
}
② 真实角色
/**
* 真实角色
* 老板
*/
class Boos implements SignContract{
@Override
public void signContract() {
System.out.println("和***公司签订合同");
}
}
③ 动态处理器
/**
* 动态代理类
* 需要实现 InvocationHandle接口,并实现invoke方法
* public static Object newProxyInstance(ClassLoader loader,
* Class<?>[] interfaces,
* InvocationHandler h)
*/
public class JdkDynamicProxy implements InvocationHandler {
//目标对象
private Object target;
public Object build(Object target){
this.target=target;
//给目标对象生成代理对象
Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
return proxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("签合同之前");
Object obj = method.invoke(target, args);
System.out.println("签合同之后");
return obj;
}
}
Proxy.newProxyInstance()方法三个参数:
ClassLoader loader
:指定当前目标对象使用的类加载器,获取加载器的方法是固定的Class[] interfaces
:指定目标对象实现的接口的类型,使用泛型方式确认类型InvocationHandler:
指定动态处理器,`执行目标对象的方法时,会触发事件处理器的方法④ 测试
public class TestJdkProxy {
public static void main(String[] args) {
//获取代理对象
JdkDynamicProxy jdkPro=new JdkDynamicProxy();
SignContract signContract = (SignContract) jdkPro.build(new Boos());
signContract.signContract();
}
}
特点:JDK 实现动态代理需要实现类通过接口定义业务方法
缺点:对于没有接口的类,如何实现动态代理呢,这就需要 CGLib 了
CGLib 采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中
采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
采用 CGLIB 代理方式时需要导入 jar 文件:cglib.jar 和 asm.jar
代理类生成器
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 o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("签合同之前");
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("签合同之前");
return result;
}
}
测试
public class CglibProxyTest {
public static void main(String[] args) {
CglibProxy cglibProxy=new CglibProxy();
SignContract proxyInstance = (SignContract) cglibProxy.getInstance(new Boos());
proxyInstance.signContract();
}
}
由于CGLib由于是采用动态创建子类的方法,对于final修饰的方法无法进行代理。
JDK 动态代理:
能够继承静态代理的全部优点.并且能够实现代码的复用.
动态代理可以处理一类业务.只要满足条件 都可以通过代理对象进行处理.
动态代理的灵活性不强.
JDK 的动态代理要求代理者必须实现接口, , 否则不能生成代理对象.
CGLIB 动态代理:
不管有无接口都可以创建代理对象.
cglib 创建的代理对象是目标对象的子类.
不能对 final 修饰的类进行代理
原文:https://www.cnblogs.com/lzhya/p/12591539.html