引言:
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/
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类是无法进行代理的哦。
相信能看到这里的,都是和笔者一样具有很大求知欲的人,望我们一起进步。