静态代理,动态代理,Cglib代理

Spring核心:AOP
AOP(Aspect Oriented Programming面向切面编程):采用横向抽取 的方式,取代了传统的纵向体系 的重复性编码。SpringAOP采用代理模式实现了横向扩展,它不需要任何类加载器或第三方编译,自spring2.5以后,引入AspectJ作为其AOP的核心实现。AspectJ是一个开源的、专门致力于AOP的一个框架,它是java语言的扩展,提供对代码横向扩展(织入 )。
SpringAOP的底层核心(重要)
Spring如何实现“横向扩展”呢?AspectJ+ Java动态代理+Cglib代理
Java的代理模式
在现实生活中,我们八维想请刘德华做一个励志演出,那么你能不能见到其本人?不能,你见到的他的经纪人(代理人)!我们如果想请刘德华来演出,必须要和经纪人来谈,那么经纪人做什么事情呢?我们请经纪人来八维谈演出的事情(经纪人和刘德华的目标是相同的,演出的目标),但是这个经纪除了演出以外,他还要收首付款,定时间(周六上午),到周六早上,真正演出的是刘德华,是经纪人“调用”刘德华来演出的,我们尤总根本没见过刘德华本人,演出完毕后,刘德华走人,那么经纪人还要收尾款!
在以上的案例中,经纪人充当了代理人,代理人和被代理人的目标是一样的,但是代理人做的事情要比被代理做的多,我们称这个代理人对目标(被代理人)进行了增强或扩展。
静态代理
代理对象和目标对象(被代理的对象),它们有一个相同的目标,在java实现里,这个“相同的目标”就是一个接口,它们同时实现了此接口。
接口:代理对象和目标对象需要共同实现的目标方法

/**
 * 这个接口是代理人和被代理需要共同实现的接口
 * 
 * @author zhaihl
 *
 */
public interface IPerformService {
    /**
     * 演出
     */
    public void perform();
}

明星

public class StarPerform implements IPerformService {

    @Override
    public void perform() {
        System.out.println("刘德华唱冰雨");
    }

}

代理人(经纪人):对明星表演这个事情做了一个增强/扩展

/**
 * 经纪人
 * 
 * @author zhaihl
 *
 */
public class AgentPerform implements IPerformService {

    private StarPerform target;

    public AgentPerform(StarPerform target) {
        this.target = target;
    }

    @Override
    public void perform() {
        System.out.println("收首付款");
        System.out.println("定时间");

        System.out.println("================华丽的分隔线==================");
        // 真正唱歌的是刘德华!
        target.perform();
        System.out.println("================华丽的分隔线==================");

        System.out.println("收尾款");

    }

}

邀请者

/**
 * 邀请者
 * 
 * @author zhaihl
 *
 */
public class ProxyTest {
    public static void main(String[] args) {
          AgentPerform agent = new AgentPerform(new StarPerform());
          agent.perform();

    }
}

静态代理需要代理对象和目标对象共同实现同一个接口,如果接口方法发生改变,那么代理对象和目标对象的方法都将发生改变(因为它们都实现这个接口)!
动态代理
如果刘德华的经纪人没那么主动,来八维做表演由刘德华决定,而经纪人只是跟着刘德华做事,刘德华做什么事,代理就做什么事,那么这个代理没有决定权,它不需要实现接口,由刘德华实现接口(来八维做演出),经纪人只要跟着刘德华做,这种方式,我们称之为动态代理。如果接口方法发生改变,只需要刘德华一人改变,这个经纪人只是一个“跟屁虫”!
接口

/**
 * 这个接口是代理人和被代理需要共同实现的接口
 * 
 * @author zhaihl
 *
 */
public interface IPerformService {
    /**
     * 演出
     */
    public void perform();
}

明星

public class StarPerform implements IPerformService {

    @Override
    public void perform() {
        System.out.println("刘德华唱冰雨");
    }

}

经纪人:它要做的事情是跟着刘德华走的,刘德华实现什么接口,它跟着实现什么接口,那么我们说,这个经纪人要做的事情是“动态的”。

public class AgentProxy {

    private StarPerform target;

    public AgentProxy(StarPerform target) {
        this.target = target;
    }

    /**
     * 
     * @return 代理类(经纪人要做的事情)
     */
    public Object getProxyInstance() {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                new InvocationHandler() {
                    // InvocationHandler:目标类所实现的接口里定义的方法操作

                    /**
                     * 就是代理类要实现的方法(自来于目标类实现的接口里的定义)
                     * proxy:代理类
                     * method代理的方法
                     * args:代理的方法参数
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        System.out.println("收首付款");
                        System.out.println("定时间");

                        System.out.println("================华丽的分隔线==================");
                        // 真正唱歌的是刘德华!
                        method.invoke(target, args);
                        System.out.println("================华丽的分隔线==================");

                        System.out.println("收尾款");

                        return null;
                    }

                });
    }

调用者

/**
 * 调用者
 * 
 * @author zhaihl
 *
 */
public class ProxyTest {
    public static void main(String[] args) {


     IPerformService agent = (IPerformService) new AgentProxy(new               StarPerform()).getProxyInstance();
     agent.perform();

    }
}

动态创建的实现类是匿名的,我们如何拿到它实例对象呢?因为它和目标类共同实现了接口,换言之,这个类(代理类)和目标类都是接口的子类,所以我们直接将返回的对象声明其父类。
动态代理特点:代理类实现的接口是动态创建的,根据目标类来创建(目标类实现什么接口,我就是实现什么接口),动态代理和静态代理都需要实现接口,我们在编程中,如果想对没有实现任何接口的类做代理,如果实现?
Cglib代理
cglib(Code Generation Library)是一个开源的,高效的代码生成类库。cglib代理又被称为“子类”代理。它的实现方式是在内存中创建一个目标的子类,通过子类扩展父类的方法。在spring里,cglib代理方式被集成到spring核心中,我们想使用 cglib代理,只需要导入spring-core-xxx.jar
匿名子类:

public class CgProxy implements MethodInterceptor {
    private StarPerform target;

    public CgProxy(StarPerform target) {
        this.target = target;
    }

    /**
     * 创建目标类的匿名子类
     * 
     * @return
     */
    public Object getProxyInstance() {
        // 工具类--创建匿名子类
        Enhancer en = new Enhancer();
        // 父类:目标类
        en.setSuperclass(target.getClass());
        // 设置回调
        en.setCallback(this);
        // 返回代理对象(目标类的子类)
        return en.create();
    }

    /**
     * 回调 proxy:代理对象 method:目标类的要做的事情(执行方法) args:目标类执行的方法参数 mp:我们要扩展的父类方法
     * 
     */
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy mp) throws Throwable {
        System.out.println("收首付款");
        System.out.println("定时间");

        System.out.println("================华丽的分隔线==================");
        // 真正唱歌的是刘德华!
        Object obj = method.invoke(target, args);

        System.out.println("================华丽的分隔线==================");

        System.out.println("收尾款");
        return obj;
    }

调用

public class ProxyTest {
    public static void main(String[] args) {

        StarPerform st = (StarPerform) new CgProxy(new StarPerform()).getProxyInstance();
        st.perform();
    }
}

SpringAOP的核心就是代理,那么它如何选择使用何种代理呢?
如果目标类实现了某接口,选择动态代理,如果目标类没有实现任何接口,使用cglib代理!!!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值