SpringAop解析(上)
Aop(Aspect Oriented Programming):面向切面编程
在Aop的底层是基于一个动态代理的模式来实现的,简单来说,Aop就是一个规范化的动态代理。
为什么这么说呢?因为在Java中,动态代理本身是一项十分灵活的技术,越灵活的技术掌握难度自然也越高。在使用传统的方式创建代理的时候,是可以有多种表达的形式的,两个人可能会有两种不同的表达形式,这样在项目中可能会碰到一些不必要的麻烦,于是便有人将它进行了一种规范化,将它的表达形式进行了一个统一,让它在掌握时更加的容易,在使用的时候更加的轻松。
面向切面编程,将交叉业务逻辑代码封装成切面,利用Aop容器的功能将切面放到主业务逻辑代码里面,交叉业务逻辑代码指的就是与主业务逻辑无关的代码,像事务、日志、缓存等。
在我们的项目中,使用传统的编码手段编写业务代码时,每一个功能的业务代码都极为繁琐,比如一个用户新增的业务,咱们得对它进行日志输出,对它的权限进行管理,同时还要对它进行事务管理,在这种情况下,咱们一个新增业务中,数十行代码里,新增的代码也就那么几行。况且咱们一个项目中不是只有一个新增的业务,还会用许多的业务功能,这样就导致编码人员不能全身心的将精力投放到主业务中。如下图所示。
为了改变这种局面,于是就有人想到了一个办法,将除去主业务的代码重新放到另外一个地方,在需要的时候再去调用这些代码。在这里就有了切面的概念,将方法注入到接口调用的某个地方(切点)。这样做的好处,不仅大大的减少了项目的代码量,还大大的增加了代码的可维护性与可读性,同时也能使编码人员在项目中能够将更多的精力放到主业务逻辑上。
什么是动态代理
动态代理就是在程序运行的时候,创建一个代理类,在代理类中创建一个代理对象,被代理的那个对象称之为目标对象,然后代理对象对目标对象中的方法进行功能性的增强。动态代理就是实现这个过程的一个技术。
代理类在程序运行期间创建的代理对象就称之为动态代理对象。在这种情况下呢,创建的代理对象,它不是java中已经定义好的,而是在运行的时候根据我们动态代理对象中的指示,动态生成的。也就是说,你想获取哪个对象的代理,动态代理就会为你动态的生成这个对象的代理对象
动态代理的优势
动态代理在生成代理对象的过程中,目标是不变的,代理对象中的方法是目标对象方法的增强方法。可以理解为在运行期间,对象中方法进行动态拦截,并在拦截方法的前后执行功能操作,在这种情况下呢,可以让你可以在不用修改源码的情况下,增强一些方法;在方法的前后你可以做你任何想做的事情。
动态代理的实现
Aop动态代理的实现方式有两种,分别是基于JDK的动态代理和CGLIB的动态代理
基于JDK动态代理的实现
在基于JDK的动态代理的实现中有两个重要的接口和类:InvocationHandler, Proxy
InvocationHandler接口
是给代理实例的调用处理程序实现的接口。每个代理实例都会有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法。
Proxy类
JDK中用来生成代理对象的类。
定义一个例子的接口(interface )
package com.spring.proxy;
public interface Example {
void hello(String name);
}
然后给这个接口定义一个实现类
package com.spring.proxy;
public class ExampleImpl implements Example {
@Override
public void hello(String name) {
System.out.println("How are you recently "+name);
}
}
在写好这个接口的实现类后,再来实现一个代理类,这个代理类必须实现InvocationHandler接口,代理类如下。
package com.spring.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxy implements InvocationHandler {
//在代理类中定义一个对象
private Object target;
//给这个对象赋值
public JDKProxy(Object target){
this.target=target;
}
//创建代理
public Object newProxy(){
return Proxy.newProxyInstance(
//获取到target是由哪个类加载器来加载的
target.getClass().getClassLoader(),
//获取到动态生成的类的接口
target.getClass().getInterfaces(),
this
);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("---------- 在业务方法调用之前可以进行前置增强 ------------");
//利用反射机制调用方法
Object nv = method.invoke(target, args);
System.out.println("---------- 在业务方法调用之后可以进行前置增强 ------------");
return nv;
}
}
在完成代理类后,咱们写个简单的示例将方法调用一下。
package com.spring.proxy;
import com.sun.org.apache.bcel.internal.generic.NEW;
public class JDKProxyTest {
public static void main(String[] args) {
//获取到需要代理的对象
Example example = new ExampleImpl();
//获取带代理类,将需要代理的对象放进去
JDKProxy jdkProxy = new JDKProxy(example);
//获取到代理对象
Example newProxy =(Example) jdkProxy.newProxy();
newProxy.hello("王麻子");
}
}
结果如下:
CGLIB的动态代理的实现
CGLIB是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。Hibernate支持它来实现PO(Persistent Object 持久化对象)字节码的动态生成。
实现cglib动态代理有一个核心的类Enhancer,具体实现过程与jdk的动态代理极为相似。
CGLIB动态代理示例
首先咱们先创建一个Maven项目,因为使用CGLIB动态代理需要导入cglib的依赖。
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1_3</version>
</dependency>
在导入完cglib的依赖后,我们再写一个例子类,在这个类中实现一个目标对象,这个类中不用实现任何接口,仅需要一个测试方法即可。
package com.spring.cglib;
public class Example {
public void Hello(){
System.out.println("Example : Hello");
}
}
接下来咱们开始实现代理类,在实现代理类时需要继承cglib中的MethodInterceptor接口。
package com.spring.cglib;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class Proxy implements MethodInterceptor {
/**
* obj:是cglib生成的代理对象
* method:被代理的目标对象
* args:给方法加入参数
* proxy:代理方法
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("----------在方法调用之前的----------");
Object cb = proxy.invokeSuper(obj, args);
System.out.println("----------在方法调用之后的---------");
return cb;
}
}
接下来咱们写一个Test 类来测试咱们的整个过程输出的结果。
package com.spring.cglib;
import net.sf.cglib.proxy.Enhancer;
public class Test {
public static void main(String[] args) {
// 通过CGLIB获取代理对象
Enhancer enhancer = new Enhancer();
//设置获取到的代理对象的父类
enhancer.setSuperclass(Example.class);
//设置代理对象的回调对象
enhancer.setCallback(new Proxy());
//创建代理对象
Example pro =(Example) enhancer.create();
//获取目标对象
pro.Hello();
}
}
输出结果如下