AOP概念与运行原理

引言:

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

技术点:
1、反射(reflect)

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

PS:顺便提一个有意思的情况,笔者亲身试验的:比如说在Integer的List中放置一个String是否可以实现呢?在反射就可以实现哦,下面是实现的代码:

            ArrayList<Integer> list = new ArrayList<Integer>();
            Method method = list.getClass().getMethod("add", Object.class);
            method.invoke(list, "我是String");
            System.out.println(list.get(0));

            //打印结果:我是String

以下是反射的一般作用:

  • 在运行时判断任意一个对象所属的类

  • 在运行时构造任意一个类的对象

  • 在运行时判断一个类所具有的成员变量和方法

  • 在运行时调用任意一个对象的方法

  • 生成动态代理

面向切面编程(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接口的子类:

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/

点击下载编写CGlib动态代理测试所需jar包

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类是无法进行代理的哦。

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

    原文作者:AOP
    原文地址: https://blog.csdn.net/u012403290/article/details/64443021
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞