Java设计模式-代理模式

写在前面:本来是想写Spring AOP原理的,分析下AOP就是代理模式的实现,这儿就先从代理模式讲起。

什么是代理模式

给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用,防止直接访问目标对象给系统带来的不必要复杂性。
代理对象:起到中介作用,连接客户端和目标对象

Java有3种代理模式

静态代理

静态代理即在编译期创建代理对象,特点:代理类与目标类需要实现相同的接口

代码示例:
接口类

public interface BuyTicketIface {
    /**
     * 买电影票
     */
    void buyMovieTicket();
}

目标类

public class BuyTicketIml implements BuyTicketIface {
    @Override
    public void buyMovieTicket() {
        System.out.println("xx买电影票");
    }
}

代理类

public class BuyTicketProxy implements BuyTicketIface {
    private BuyTicketIface buyTicket;

    public BuyTicketProxy() {
    }

    public BuyTicketProxy(BuyTicketIface buyTicket) {
        this.buyTicket = buyTicket;
    }

    @Override
    public void buyMovieTicket() {
        System.out.println("给钱");
        buyTicket.buyMovieTicket();
        System.out.println("买到票");
    }
}

测试类

public class BuyTicketTest {
    public static void main(String[] args) {
        //创建目标对象
        BuyTicketIface buyTicket = new BuyTicketIml();
        //创建代理对象
        BuyTicketProxy proxy = new BuyTicketProxy(buyTicket);
        //购票
        proxy.buyMovieTicket();
    }
}

输出结果

给钱
xx买电影票
买到票

动态代理(Jdk代理)

动态代理,即创建代理对象的方式为在jvm运行时通过反射动态创建,与静态代理在编译期就创建代理对象相比减少了内存的占用,同时减少了对业务接口的依赖,降低了耦合度。

动态代理特点:
- 目标对象实现类接口
- 代理对象通过JDk API动态的在内存中创建

Jdk创建代理对象的类java.lang.reflect.Proxy,创建方法newProxyInstance

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

参数说明:
loader - 定义代理类的类加载器
interfaces - 代理类要实现的接口列表(即目标对象实现的接口列表)
h - 指派方法调用的调用处理程序

示例:
接口

/**
 * @Description 接口
 * @date 2018/8/7 16:50
 */
public interface FlyIface {
    void fly();
}

目标类

public class Dog implements FlyIface {
    private String name;

    public Dog() {
    }

    public Dog(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void fly() {
        System.out.println("....dog fly...."+name);
    }

}

public class Dream implements FlyIface {
    @Override
    public void fly() {
        System.out.println(".....dream fly....");
    }
}

代理类
需要实现接口InvocationHandler

public class FlyProxy implements InvocationHandler {
    private Object target;

    public Object bind(Object target) {
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("proxy class:"+proxy.getClass().getName()+"\n method:"+method.getName());
        System.out.println("目标类执行前处理");
        Object result = method.invoke(target,args);
        System.out.println("目标类执行结束处理");
        return result;
    }
}

测试类

public class DynamicProxyTest {
    public static void main(String[] args) {
        FlyProxy proxy = new FlyProxy();
        FlyIface fly = (FlyIface)proxy.bind(new Dog("dd"));
        fly.fly();
    }
}

输出结果

proxy class:com.sun.proxy.$Proxy0
 method:fly
目标类执行前处理
....dog fly....huahua
目标类执行结束处理

Cglib代理

Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)。Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类。

有或者没有实现接口的类都可以通过Cglib代理加载。使用Cglib代理需要注意的事项:
1.需要引入cglib的jar文件,由于Spring的核心包中已经包括了Cglib功能,所以也可以直接引入spring-core-${version}.jar
2.目标类不能为final,否则报错
3.目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法
示例:
目标类

public class Duck {
    public void yell() {
        System.out.println("Duck quack");
    }
}

代理类
Cglib子类代理工厂

public class CglibProxy implements MethodInterceptor {
    public Object bind(Object target) {
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(target.getClass());
        //设置回调
        enhancer.setCallback(this);
        return enhancer.create();//创建代理对象
    }

    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable{
        System.out.println("目标类方法执行前处理");
        proxy.invokeSuper(object,args);
        System.out.println("目标类方法执行结束处理");
        return null;
    }
}

测试类

public class CglibTest {
    public static void main(String[] args) {
        CglibProxy cglibProxy = new CglibProxy();
        Duck duck = (Duck) cglibProxy.bind(new Duck());
        duck.yell();
    }
}

输出结果

目标类方法执行前处理
Duck quack
目标类方法执行结束处理

输出结果表明,在目标类Duck.yell()方法执行前后,代理进行了拦截。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值