JAVA设计模式之代理模式

代理模式:动态代理、静态代理

注意事项:
1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。
2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。

静态代理:
静态代理类需要实现委托类实现的接口,实际业务处理由委托对象处理。
静态代理实现中,一个委托类对应一个代理类,代理类在编译期间就已经确定。

接口

public interface Subject {
    public void doSomething();
}

委托类1:

public class FatherSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("Father do something ....");
    }
}

委托类2:

public class SonSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("Son do something ....");
    }
}

代理类:

public class ProxySubject implements Subject{
    private Subject subject;
    public ProxySubject(Subject subject ){
        if (subject==null) {
            throw new RuntimeException("委托对象不能为空");
        }
        this.subject=subject;
    }
    @Override
    public void doSomething() {
        //由实际委托对象处理
        subject.doSomething();
    }
}

测试类:

Subject subject=new ProxySubject(new FatherSubject());
subject.doSomething();
subject=new ProxySubject(new SonSubject());
subject.doSomething();

测试结果:

Father do something ....
Son do something ....

动态代理:
动态代理代理的对象不确定,代理类需要实现InvocationHandler,当执行handler.doSomething()时,会调用invoke方法。

动态代理类:

public class DynamicProxy implements InvocationHandler {
    private Object target; //代理的委托对象
    public DynamicProxy(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(target, args);
    }

    public Object getInstance(){
        ClassLoader classLoader=Thread.currentThread().getContextClassLoader();
        return Proxy.newProxyInstance(classLoader, target.getClass().getInterfaces(), this);
    }
}

测试:

Subject target = new FatherSubject();
DynamicProxy dynamicProxy=new DynamicProxy(target);
Subject handler=(Subject) dynamicProxy.getInstance();
handler.doSomething();

测试结果:

Father do something ....

使用Proxy、InvocationHandler、反射实现动态代理,代理的委托对象必须是接口的实现类的对象,当没有接口时就不适应。使用CGlib的MethodInterceptor课实现无接口的动态代理。

CGlib实现动态代理

public class CglibProxy implements MethodInterceptor{
    /**
     * 委托类Class.
     */
    private Class<?> consignor;
    public CglibProxy(Class<?> consignor){
        this.consignor=consignor;
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] arg2, MethodProxy methodProxy) throws Throwable {
        return methodProxy.invokeSuper(obj, arg2);
    }

    public Object getInstance(){
        Enhancer enhancer=new Enhancer();
        enhancer.setSuperclass(consignor);
        enhancer.setCallback(this);
        return enhancer.create(); //创建代理类
    }
}

UserServiceImpl

public class UserServiceImpl {
    public void add(){
        System.out.println("UserServiceImpl add method invoked ...");
    }
}

测试:

CglibProxy cglibProxy=new CglibProxy(UserServiceImpl.class);
UserServiceImpl userServiceImpl=(UserServiceImpl)cglibProxy.getInstance();
userServiceImpl.add();

测试结果:

UserServiceImpl add method invoked ...

jdk和cglib动态代理实现的区别

1、jdk动态代理生成的代理类和委托类实现了相同的接口;
2、cglib动态代理中生成的字节码更加复杂,生成的代理类是委托类的子类,且不能处理被final关键字修饰的方法;
3、jdk采用反射机制调用委托类的方法,cglib采用类似索引的方式直接调用委托类方法;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值