AOP--从代理说起

7 篇文章 0 订阅
7 篇文章 0 订阅

      要想了解Spring Aop 我们不得不从什么是AOP说起,其实听AOP也不是一天两天了,但是真正的去了解一些东西好像也就是最近那么就先从概念性质的介绍起:


一、什么是AOP
      AOP(Aspect-OrientedProgramming,面向方面编程),其实我更习惯说是面向切面编程,因为觉得这样更形象,其实好像怎么都不如英语形象。
说到AOP,应该最先想到的应该就是OOP(Object-Oriented Programing,面向对象编程)吧,要说这两个有什么关系其实开始我觉得这两个不相关后来经过去了解学习,知道可以说AOP是OOP的补充和完善。我们知道OOP运用封装,继承,多态的概念来抽象对象,当我们需要在分散的对象上添加一些公共行为时,例如:日志单纯的OOP就没有办法解决这个问题,所以可以这样说OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。如果我们需要为每一个模块加入日志,OOP就会有大量的重复代码,如果使用AOP技术,把日志作为一个切面切入到模块中就能解决这个问题。

二、AOP中的主要名词 
1、切面(Aspect):个人理解就是被抽象出来的公共功能的一个类,在这个类里定义了切点,目标对象,Advice(通知或者增强 )
2、切入点:在切面中定义,指定Advice将被引入的一系列的连接点的集合。
3、连接点:Joinpoint,在程序中,切面将要引入的具体地方被称为连接点。
4、目标对象:就是被通知被代理的对象,需要插入切面的类,在运行时成为被代理对象
其实还有很多名词,但是我觉得知道这些就可以对AOP有一个宏观的了解了。

三、不得不说的代理
说到AOP就不得不说代理,开始学习设计模式的时候对代理模式没有特别深刻的印象,这次通过对AOP的学习又一次来学习代理模式,为什么要说代理模式呢?因为AOP的实现基础就是代理,为什么抽象出的切面可以顺利的引用到已经编译好的类或者方法中运行,都是因为为这些需要加入切面的类进行了代理,在代理里执行了切面功能。
那么就从静态代理说起吧

1、静态代理:代理
/**
 * 静态代理测试
 * @author 陈丽娜
 *
 */
public class HelloStaticProxy implements HelloWorld{
    //持有被代理对象的引用
    private HelloWorldImpl helloWorldImpl;
    
    /**
     * 构造函数,初始化时确定被代理的类
     * @param helloWorldImpl
     */
    public HelloStaticProxy(HelloWorldImpl helloWorldImpl){
        this.helloWorldImpl=helloWorldImpl;
    }
    @Override
    public void sayHello(String name) {
        before();
        helloWorldImpl.sayHello(name);
        after();
    }
     
     private void before() {
            System.out.println("Before");
      }
     
     private void after() {
            System.out.println("After");
      }    
} 

类和目标类实现相同的接口,代理类持有目标类的引用从而实现代理的效果,静态代理类如下:

可以很明显的看到静态代理的缺陷,需要建立大量的代理类。不方便复用这时候就可以考虑动态代理

2、JDK动态代理:JDK动态代理要求目标对象必须实现接口,因为创代理对象的时候是根据接口创建的,如果不实现接口,JDK则没有办法给目标对象创建代理对象。
JDK动态代理对象的实现如下:
/**
 * JDK动态代理
 * @author 陈丽娜
 *
 */
public class HelloJDKProxy implements InvocationHandler {
    //定义代理目标
    private Object target;
    
    public HelloJDKProxy(Object target){
        this.target = target;
    }
    
    /**
     * 获取代理对象
     * @return 
     */
    public <T> T getProxy(){
        return (T) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                this);        
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        before();
        Object result = method.invoke(target,args);
        after();
    /*    System.out.println("JDK实现动态代理==" + result);
        System.out.println("JDK动态代理方法==" + method);*/
        return result;
    
    }
     private void before() {
         System.out.println("JDK实现动态代理Before");
     }
     
     private void after() {
          System.out.println("JDK实现动态代理After");
     }
}


开始也说了JDK的动态代理只能为实现了接口的对象进行代理,这样就有一定的局限

3、CGLib动态代理:JDK动态代理做不到的,CBLib能给不实现 接口的 目标类提供动态代理,Spring在给某个类提供动态代理时候会自动选择。CGLib的动态代理实现如下:
/**
 * CGLib动态代理
 * @author 陈丽娜
 *
 */
public class HelloCGLibProxy implements MethodInterceptor {
    //定义全局的代理类
    private static HelloCGLibProxy instance = new HelloCGLibProxy();
    
    private HelloCGLibProxy(){        
    }
    
    public static HelloCGLibProxy getInstance(){
        return instance;
    }
    /**
     * 通过泛型获取代理目标的类型
     * @param clazz
     * @return
     */
    @SuppressWarnings("unchecked")
    public <T> T getProxy(Class<T> clazz) {
            return (T) Enhancer.create(clazz, this);
    }
    
    @Override
    public Object intercept(Object target, Method method, Object[] args,
            MethodProxy proxy) throws Throwable {
        before();
        Object result = proxy.invokeSuper(target,args);
        after();
      /*  System.out.println("CGLib动态代理==" + result);
        System.err.println("target===" + target + "method===" + method + "proxy==" + proxy);*/
        return result;
    }
    private void before() {
         System.out.println("CGLib实现动态代理Before");
    }
     
    private void after() {
          System.out.println("CGLib实现动态代理After");
    }
}

不同的代理,我们再看调用时候有什么不同:

/**
     * 静态代理使用测试
     */
    @Test
    public void StaticProxyTest(){
        HelloWorld helloWorldStaticProxy = new HelloStaticProxy(new HelloWorldImpl());
        helloWorldStaticProxy.sayHello("静态代理===陈丽娜");        
    }
    
    /**
     * JDK动态代理使用测试
     */
    @Test
    public void JDKProxyTest(){        
        HelloWorld helloWorld = new HelloJDKProxy(new HelloWorldImpl()).getProxy();
        helloWorld.sayHello("JDK代理===陈丽娜");
    }
    
    /**
     * CGLib动态代理使用测试
     */
    @Test
    public void CGlibProxyTest(){        
        HelloWorld helloWorld = HelloCGLibProxy.getInstance().getProxy(HelloWorldImpl.class);
        helloWorld.sayHello("CGLib代理===陈丽娜");
    }  


运行结果如下:
Before
Hello静态代理===陈丽娜
After
JDK实现动态代理Before
HelloJDK代理===陈丽娜
JDK实现动态代理After
CGLib实现动态代理Before
HelloCGLib代理===陈丽娜
CGLib实现动态代理After


很明显我们可以看到代码的复用情况,代理就是AOP的基础,至于AOP的实现原理下篇博客可以再探讨。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值