AOP,即面向切面编程,SpringAOP是在SpringIoC上做的扩展,是面向某一个切面或关注点,例如所有模块都用到日志功能,就可以看作将日志嵌入各个模块,这些很多模块都通用的功能就可以看作是切面,把它定义为“横切关注点”,其代码可以为各个模块复用。
AOP具有源码无关性,它可以通过预编译方式或者运行期动态代理的方式来实现。
AOP核心概念
- 连接点(JoinPoint):连接点是程序执行过程中的特定点,可以是一个方法的调用,类的初始化等。
- 通知(Advice):在某一个特定连接点运行的代码叫做通知。比如在连接点之前执行的通知叫前置通知,在连接点之后的通知叫做后置通知。
- 切入点(PointCut):切入点用来定义某个通知何时执行的一组连接点的集合。举个例子,如果某个类的一个方法调用前是一个连接点,那么切入点就是这个类的所有方法的调用前的集合。
- 方面(Aspect):通知和切入点的组合叫做方面,这个组合就定义了何时执行一组程序,以及执行什么样的程序。
- 织入(Weaving):是将方面真正的加入到程序中的过程,就行织毛衣。
- 引入(introduction):可以不显式的修改代码,就可以引入新的接口、方法或者字段。
- 目标对象(Target Object):被代理、被通知的对象。
talk is cheap,show me the code:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<!--配置被代理的对象(目标对象)-->
<bean id="testService1" class="com.wmj.aop.TestService1">
<property name="name" value="wmj"/>
</bean>
<!--配置前置通知 -->
<bean id="myMethodBeforeAdvice" class="com.wmj.aop.MyMethodBeforeAdvice"/>
<!-- 配置后置通知 -->
<bean id="myAfterReturningAdvice" class="com.wmj.aop.MyAfterReturningAdvice"/>
<!-- 配置环绕通知 -->
<bean id="myMethodInterceptor" class="com.wmj.aop.MyMethodInterceptor"/>
<!-- 配置异常通知 -->
<bean id="myThrowsAdvice" class="com.wmj.aop.MyThrowsAdvice"/>
<!-- 自定义前置通知的切入点 -->
<bean id="myMethodBeforeAdviceFilter" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="myMethodBeforeAdvice"/>
<property name="mappedNames">
<list>
<!-- 前置通知只对sayHello函数有效 -->
<!--在这里也可以使用正则表达式如say* 表示以say开头的函数,当然也可以自己列举 -->
<value>sayHello</value>
</list>
</property>
</bean>
<!-- 配置代理对象 -->
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--
ProxyFactoryBean implements TestServiceInter,TestServiceInter2{
public void sayHello();
public void sayBye();
}
-->
<!--配置接口集 -->
<property name="proxyInterfaces">
<list>
<value>com.wmj.aop.TestServiceInter</value>
<value>com.wmj.aop.TestServiceInter2</value>
</list>
</property>
<!-- 把通知织入到代理对象 -->
<property name="interceptorNames">
<!-- 相当于把MyMethodBeforeAdvice前置通知与代理对象相关联,
我们可以把通知看成是拦截器 -->
<list>
<!--使用自定义切入点来控制前置通知 -->
<value>myMethodBeforeAdviceFilter</value>
<!-- <value>myMethodBeforeAdvice</value> -->
<value>myAfterReturningAdvice</value>
<value>myMethodInterceptor</value>
<value>myThrowsAdvice</value>
</list>
</property>
<!-- 配置被代理对象,可以指定 -->
<property name="target" ref="testService1"/>
</bean>
</beans>
public class MyAfterReturningAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
// TODO Auto-generated method stub
System.out.println("关闭资源");
}
}
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
/**
* method:被调用方法名
* args:给method传递的参数
* target:目标对象
*/
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
// TODO Auto-generated method stub
System.out.println("记录日志......"+method.getName());
}
}
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation arg0) throws Throwable {
// TODO Auto-generated method stub
System.out.println("调用方法前...");
Object obj = arg0.proceed();
System.out.println("调用方法后...");
return obj;
}
}
public class MyThrowsAdvice implements ThrowsAdvice {
//参数method要引入反射包
public void afterThrowing(Method m,Object[] os,Object target,Exception throwable){
System.out.println("出现异常 "+throwable.getMessage());
}
}
public interface TestServiceInter {
public void sayHello();
}
public interface TestServiceInter2 {
public void sayBye();
}
public class TestService1 implements TestServiceInter,TestServiceInter2 {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void sayHello() {
System.out.println("hello "+name);
}
@Override
public void sayBye() {
// TODO Auto-generated method stub
System.out.println("bye "+name);
//下面代码检测异常通知
//int i = 9/0;
}
}
public class App {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("com/wmj/aop/beans.xml");
TestServiceInter tsi = (TestServiceInter) ac.getBean("proxyFactoryBean");
tsi.sayHello();
TestServiceInter2 tsi2 = (TestServiceInter2) tsi;
tsi2.sayBye();
}
}