AOP概念与运行原理

转载于:https://blog.csdn.net/u012403290/article/details/64443021

引言

AOP指的就是面向切面编程,在实际的开发和工作中很多地方都深有体现,比如权限控制,控制全局状态等。接下来会详细阐述AOP的概念,给出对应的DEMO来深入学习实践,探讨AOP的意义。

技术点: 

1、反射(reflect)

在运行状态中,对于任意一个类,都能够知道这个类的属性和方法。对于任意一个对象,都能调用它的任意一个方法和属性(private的方法也可以调用,不用觉得封装就变得没有意义了,笔者觉得存在就是合理的)。这种动态获取的信息以及动态调用对象的方法称为反射

以下是反射的一般作用:在运行时判断任意一个对象所属的类、  在运行时构造任意一个类的对象、在运行时判断一个类所具有的成员变量和方法、在运行时调用任意一个对象的方法、生成动态代理

面向切面编程(AOP)

1、概念:AOP是建立在Java的反射基础之上,具体是指散落在程序中的公共部分提取出来,做成了切面类,这样做的好处在于代码的可重用。一旦涉及到该功能的需求发生变化,只要修改该代码就行。AOP的实现主要是由JDK的动态代理与CGLIB代理。下面会具体介绍这两种代理。

2、意义:增强类的功能(在目标对象的方法执行之间和执行之后)。

JDK动态代理:

a、先定义一个接口,这个接口中的方法是“目标方法”

package com.brickworkers;

public interface Sky {

    public void rain();

}

b、接着写一个这个接口的具体实现:

package com.brickworkers;

public class SkyImpl implements Sky{

    @Override
    public void rain() {
        System.out.println("it`s raining");
    }


}

c、如果要完成动态代理,首先需要定义一个InvocationHandler接口的子类:

代理知识回顾:

目前Java开发包中包含了对动态代理的支持,但是其实现只支持对接口的的实现。 其实现主要通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。 

  Proxy类主要用来获取动态代理对象,调用newProxyInstance()方法实现。每一个动态代理类都必须要实现 InvocationHandler 这个接口,InvocationHandler接口用来约束调用者实现,通过invoke方法利用java的反射机制实现对相关方法的监听。

      动态代理是很多框架和技术的基础, spring 的AOP实现就是基于动态代理实现的。

package com.brickworkers;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyInvocationHandler implements InvocationHandler {

    //目标对象
    private Object obj = null;


    //获取目标对象的代理对象
    public Object getProxy(Object obj){
        this.obj = obj;
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
    }

    //控制执行目标对象的方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("目标对象方法执行之前");
        Object result = method.invoke(obj, args);
        System.out.println("目标对象方法执行之后");
        return result;
    }

}

d:JDK动态代理测试类:

package com.brickworkers;

public class ProxyTest {

    public static void main(String[] args) {
        //实例化InvocationHandler
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
        //生产代理对象
        Sky sky = (Sky) myInvocationHandler.getProxy(new SkyImpl());
        sky.rain();
    }

}

//执行结果:  目标对象方法执行之前
//            it`s raining
//          目标对象方法执行之后

看到这里相信大家和我一样就很疑惑,为什么JDK动态代理只能局限于接口呢?对此,笔者查阅了一些技术文档和JDK动态代理的源码,发现在反编译产生的proxyTest.class中,类的定义如下:

import dynamic.proxy.UserService;  
import java.lang.reflect.*;  

public final class $ProxyTest extends Proxy  
    implements Sky
{ 
    ......
}

从反编译的源码可以看出,proxyTest继承了Proxy,然而在Java中只支持单继承,但是可以实现多个接口,所以JDK动态代理只能局限于接口。

那么JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,要实现动态代理要怎么办呢?这个时候就需要CGLib动态代理啦。

CGLib动态代理:

CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有分类方法的调用,顺势织入和横切逻辑。-http://blog.csdn.net/yakoo5/article/details/9099133/

a、定义一个目标对象:

package com.brickworkers;

public class Color {

    public void showColor(){
        System.out.println("red");
    }

}

b、如果要完成动态代理,首先需要定义一个MethodInterceptor接口的子类:

package com.brickworkers;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class MyCglib implements MethodInterceptor {

    //目标对象
    private Object obj = null;

    public Object getProxy(Object obj){
        this.obj = obj;
        Enhancer enhancer = new Enhancer();  
        enhancer.setSuperclass(obj.getClass());
        // 回调方法  
        enhancer.setCallback(this);  
        // 创建代理对象  
        return enhancer.create();

    }

    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("目标对象方法执行之前");
        Object result = methodProxy.invoke(obj, args);
        System.out.println("目标方法执行之后");
        return result;
    }

}

c、CGLib动态代理测试类:

package com.brickworkers;

public class CGLibTest {

    public static void main(String[] args) {
        MyCglib myCglib = new MyCglib();
        Color color = (Color) myCglib.getProxy(new Color());
        color.showColor();
    }
}
//执行结果:目标对象方法执行之前
//              red
//          目标方法执行之后

最后,还有一点需要注意:因为CGLib动态代理是创建一个子类来实现的,那么对于继承的定义,final类是无法进行代理的哦。

相信能看到这里的,都是和笔者一样具有很大求知欲的人,望我们一起进步。



猜你喜欢

转载自blog.csdn.net/oyeyuanxinzhizhu1/article/details/80117338