一、什么是Spring Aop?
AOP (Aspect-Oriented Programming :面向切面编程)就是将那些与业务无关,却为业务模块所共同调用的逻辑(例如事务处理、日志管理、权限控制等)封装抽取成一个可重用的模块,这个模块被命名为“切面”( Aspect ),便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
二、Spring Aop的实现原理
1.首先,我们抽象一个接口Demo,定义俩个接口方法,一个是在被代理对象要执行方法之前执行的方法,我们取名为one,第二个方法就是在被代理对象执行方法之后执行的方法,我们取名为double:
public interface Demo{
void one(Method method);
void double(Method method);
}
2.创建一个类实现Demo接口:
public class DemoImpl implements Demo{
@Override
public void one(Method method) {
System.out.println(new Date() + method.getName() + " hello ,one...");
}
@Override
public void double(Method method) {
System.out.println(new Date() + method.getName() + " hello ,double");
}
}
3.创建动态代理类:
public class DtdlHandler implements InvocattionHandler {
//创建调用对象
private Object proxy;
//创建目标对象
private Object target;
public Object bind(Object target, Object proxy) {
this.target = target;
this.proxy = proxy;
return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), thistarget.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
//反射得到操作者实列
Class clazz = this.proxy.getClass();
//反射得到操作者的one方法
Method one= clazz.getDeclaredMethod("one", new Class[]{Method.class});
//反射执行one方法
start.invoke(this.proxy, new Object[]{this.proxy.getClass()});
//执行要处理对象的原本方法
method.invoke(this.target, args);
//反射得到操作者的double方法
Method double= clazz.getDeclaredMethod("double",new Class[]{Method.class});
//反射执行end方法
end.invoke(this.proxy, new Object[]{method});
return result;
}
}
4.编写代码进行测试:
public class Test01{
public static void main(String[] args) {
Demo demo = (Demo) new DtdlHandler().bind(new Hello(),new DemoImpl());
}
}
通过上面例子,我们可以发现通过动态代理和反射技术,已经基本实现了AOP的功能,如果我们只需要在方法上执行前打印日志,则可以不实现double()方法,这样就可以控制打印的实际了,如果我们想让指定的方法打印日志,我们只需要在invoke()方法中加一个对method名字的判断,method的名字可以写在xml文件中,这样我们就可以实现以配置文件进行解耦了,这样我们就实现了一个简单的Spring AOP框架。
三、Spring Aop中的常见术语
-
Aspect:表示切面。切入业务流程的一个独立模块。例如,前面案例的VerifyUser类,一个应用程序可以拥有任意数量的切面。
- Join point:表示连接点。也就是业务流程在运行过程中需要插入切面的具体位置。例如,前面案例的AopEmailNotice类的setTeacher方法就是一个连接点。
- Advice:表示通知。是切面的具体实现方法。可分为前置通知(Before)、后置通知(AfterReturning)、异常通知(AfterThrowing)、最终通知(After)和环绕通知(Around)五种。实现方法具体属于哪类通知,是在配置文件和注解中指定的。例如,VerifyUser类的beforeAdvice方法就是前置通知。
- Pointcut:表示切入点。用于定义通知应该切入到哪些连接点上,不同的通知通常需要切入到不同的连接点上。例如,前面案例配置文件的<aop:pointcut>标签。
- Target:表示目标对象。被一个或者多个切面所通知的对象。例如,前面案例的AopEmailNotice类。
- Proxy:表示代理对象。将通知应用到目标对象之后被动态创建的对象。可以简单地理解为,代理对象为目标对象的业务逻辑功能加上被切入的切面所形成的对象。
- Weaving:表示切入,也称为织入。将切面应用到目标对象从而创建一个新的代理对象的过程。这个过程可以发生在编译期、类装载期及运行期。
四、小结
Spring AOP基于动态代理实现:
- 如果被代理的对象,没有实现某个接口,就无法使用JDK Proxy去进行代理了,这时候Spring AOP会使用Cglib,基于继承的方式,生成一个被代理对象的子类来作为代理(cglib 动态代理的核心是MethodInterceptor接口和Enhancer类);
- 如果被代理的对象,没有实现某个接口,就无法使用JDK Proxy去进行代理了,这时候Spring AOP会使用Cglib,基于继承的方式,生成一个被代理对象的子类来作为代理(cglib 动态代理的核心是MethodInterceptor接口和Enhancer类);