每本Spring的书在介绍AOP之前,总能有一箩筐的术语,看半天似懂非懂,也就没兴趣再继续学习下去,其实并没有这么复杂。
难懂的定义我们就不贴了,就说说咱们通俗的解释,下面让我们结合代码来理清楚各个术语的含义
一、Advice(通知,叫增强更贴切低啊,也更好理解)
增强可以这么理解:为某些方法增加某些功能,这些功能可以安全、事物、日志等;
增强分为前置增强(Before Advice):对方法执行前进行的增强
后置增强(After Advice):对方法执行后进行的增强
环绕增强(Around Advice):可以理解为前置增强跟后置增强的合体
抛出增强(Throw Advice):方法抛出异常后退出执行的增强
引入增强(Introduction Advice):动态的让被增强的类实现一个接口
代码伺候:
先看前置增强、后置增强以及环绕增强,下面是jdk动态代理的代理类
package com.bckj.proxy.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class Invo implements InvocationHandler {
private Object target;
public Invo(Object target) {
this.target = target;
}
@Override
public Object invoke(Object o, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(target, args);
after();
return result;
}
private void before(){
System.out.println("------method start------");
}
private void after(){
System.out.println("------method end------");
}
}
上面例子中的invoke方法中before方法就叫前置加强,像after这样的方法就叫后置加强,before跟after兼具就叫环绕加强,下面看Spring Aop的代码
接口:
package test;
/**
* Created by DoodleJump on 2017/5/16.
*/
public interface Greeting {
void sayHello(String name);
}
实现类:
package test;
import org.springframework.stereotype.Component;
/**
* Created by DoodleJump on 2017/5/16.
*/
@Component
public class GreetingImpl implements Greeting {
@Override
public void sayHello(String name) {
System.out.println("Hello! "+name);
}
}
前置增强类(实现org.springframework.aop.MethodBeforeAdvice接口):
package test;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* 前置增强
*/
@Component
public class GreetingBeforeAdvice implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println(method.getName()+" start!");
}
}
后置增强类(实现org.springframework.aop.AfterReturningAdvice接口):
package test;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* 后置增强
*/
@Component
public class GreetingAfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println(method.getName()+" end!");
}
}
环绕增强类(实现org.aopalliance.intercept.MethodInterceptor接口):
package test;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.stereotype.Component;
/**
* 环绕增强
*/
@Component
public class GreetingAroundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
before(methodInvocation);
Object result = methodInvocation.proceed();
after(methodInvocation);
return result;
}
private void before(MethodInvocation methodInvocation){
System.out.println(methodInvocation.getMethod().getName()+" start!");
}
private void after(MethodInvocation methodInvocation){
System.out.println(methodInvocation.getMethod().getName()+" end!");
}
}
就以环绕增强类为例,spring配置文件的配置如下
<context:component-scan base-package="test" />
<bean id="greetingProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--需要代理的接口-->
<property name="proxyInterfaces" value="test.Greeting"/>
<!--接口实现类-->
<property name="target" ref="greetingImpl"/>
<!--拦截器名称(也就是增强类名称)-->
<property name="interceptorNames">
<list>
<value>greetingAroundAdvice</value>
</list>
</property>
</bean>
测试类:
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by DoodleJump on 2017/5/16.
*/
public class Client {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring/ApplicationContext.xml");
Greeting greeting = (Greeting)context.getBean("greetingProxy");
greeting.sayHello("Jack");
}
}
测试结果:
下面来看抛出增强:
抛出增强类(实现org.springframe.aop.ThrowAdvice接口,该接口仅仅为标识接口,没有抽象方法,但是实现类必须得有afterThrowing这个方法,不然spring在反射的时候会抛出java.lang.IllegalArgumentException: At least one handler method must be found in class [class test.GreetingThrowAdvice] 这个异常)
package test;
import org.springframework.aop.ThrowsAdvice;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* Created by DoodleJump on 2017/5/16.
*/
@Component
public class GreetingThrowAdvice implements ThrowsAdvice {
public void afterThrowing(Method method,Object[] args,Object target,Exception e){
System.out.println("----------Throw Exception----------");
System.out.println("Target Class: "+target.getClass().getName());
System.out.println("Method Name: "+method.getName());
System.out.println("Exception Message: "+e.getMessage());
System.out.println("-----------------------------------");
}
}
让实现类的方法抛出一个异常:
@Component
public class GreetingImpl implements Greeting {
@Override
public void sayHello(String name) {
System.out.println("Hello! "+name);
throw new RuntimeException("Error");
}
}
配置文件的话就把增强类名称改为greetingThrowAdvice,测试类不变,测试结果:
引入增强:
动态实现的接口:
package test;
/**
* Created by DoodleJump on 2017/5/16.
*/
public interface Apology {
void saySorry(String name);
}
引入增强类(继承org.springframework.aop.support.DelegationIntroductionInterceptor并实现动态接口):
package test;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
import org.springframework.stereotype.Component;
/**
* Created by DoodleJump on 2017/5/16.
*/
@Component
public class GreetingIntroAdvice extends DelegatingIntroductionInterceptor implements Apology {
@Override
public void saySorry(String name) {
System.out.println("Sorry! "+name);
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
return super.invoke(invocation);
}
}
spring配置文件:
<bean id="greetingProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--需要代理的接口-->
<property name="proxyInterfaces" value="test.Apology"/>
<!--接口实现类-->
<property name="target" ref="greetingImpl"/>
<!--拦截器名称(也就是增强类名称)-->
<property name="interceptorNames">
<list>
<value>greetingIntroAdvice</value>
</list>
</property>
<!--代理目标类(false:jdk代理,true:cglib代理)-->
<property name="proxyTargetClass" value="true"/>
</bean>
测试类:
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by DoodleJump on 2017/5/16.
*/
public class Client {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring/ApplicationContext.xml");
GreetingImpl greetingImpl = (GreetingImpl)context.getBean("greetingProxy");
greetingImpl.sayHello("Jack");
Apology apology = (Apology) greetingImpl;
apology.saySorry("Jack");
}
}
测试结果:
可以看到生成的代理类动态的实现了Apology这个接口。
二、Weaving(织入):对方法的增强,比如上面所说的前置增强、后置增强以及环绕增强都是织入的表现
根据不同的实现技术,AOP有三种织入的方式:
a、编译期织入,这要求使用特殊的Java编译器。
b、类装载期织入,这要求使用特殊的类装载器。
c、动态代理织入,在运行期为目标类添加增强生成子类的方式。
Spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。
三、Introduction(引入):对类的增强,比如上面所说的引入增强
四、Pointcut(切点):切入的连接点,即织入或引入发生的那个方法或类
五、Aspect(切面):增强+切点,配置如下
六、Join Point(连接点):所有可以切入的点,切点只是你选择的部分连接点