Spring07-AOP之通知
AspectJ的切入点表达式
execution(public * *(..))
指定切入点为:任意公共方法。execution(* set *(..))
指定切入点为:任何一个以“set”开始的方法。execution(* com.xyz.service.*.*(..))
指定切入点为:定义在service包里的任意类的任意方法。execution(* com.xyz.service..*.*(..))
指定切入点为:定义在service包或者子包里的任意类的任意方法。“…”出现在类名中时,后面必须跟“*”,表示包、子包下的所有类。execution(* *.service.*.*(..))
指定只有一级包下的serivce子包下所有类(接口)中的所有方法为切入点。
搭建AspectJ的开发环境
- 导入两个Jar包
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aspects-4.1.6.RELEASE.jar - 引入AOP约束
AspectJ对于AOP的实现有两种方式:
- 注解方式
- XML方式
1. 通知的用法(注解方式)
- 定义通知类
package com.caorui.aspects;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
//切面类
@Aspect //表明当前类是一个切面
public class MyAspect {
//该注解表明当前方法是前置通知方法
@Before("execution(* *..service.*.doSome(..))")
public void before() {
System.out.println("前置方法执行!");
}
//该注解表明当前方法是后置通知方法
@AfterReturning(value = "execution(* *..service.*.doOther(..))", returning = "result")
public void afterReturning(Object result) {
System.out.println("后置方法执行!目标参数的返回值是:" + result);
}
//该注解表明当前方法是环绕通知方法
@Around("execution(* *..service.*.doOther(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知:目标执行之前!");
String result = (String)pjp.proceed();
if (result != null) {
result = result.toUpperCase();
}
System.out.println("环绕通知:目标执行之后!");
return result;
}
//该注解表明当前方法是异常通知方法
@AfterThrowing(value = "execution(* *..service.*.doSome(..))", throwing = "ex")
public void throwing(Exception ex) {
System.out.println("异常通知方法执行!" + ex);
}
//该注解表明当前方法是最终通知方法:无论程序执行是否正常,该通知都会执行。类似于
try..catch中finally代码块。
@After("execution(* *..service.*.doSome(..))")
public void after() {
System.out.println("最终通知方法执行!");
}
}
- 定义目标类
package com.caorui.service;
public interface SomeService {
void doSome();
String doOther();
}
package com.caorui.service.impl;
import com.caorui.service.SomeService;
public class SomeServiceImpl implements SomeService {
public SomeServiceImpl() {
System.out.println("SomeServiceImpl.SomeServiceImpl()");
}
@Override
public void doSome() {
System.out.println("SomeServiceImpl.doSome()");
System.out.println("SomeServiceImpl.doSome()" + 1/0);
}
@Override
public String doOther() {
System.out.println("SomeServiceImpl.doOther()");
return "love";
}
}
- 注册目标类、注册切面类、注册自动代理
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 注册目标类 -->
<!-- bean的定义:以下配置相当于SomeService service = new SomeServiceImpl(); id相当于service这个引用 -->
<bean id="someServiceImpl" class="com.caorui.service.impl.SomeServiceImpl"></bean>
<!-- 注册切面,前置通知 -->
<bean id="MyAspect" class="com.caorui.aspects.MyAspect"></bean>
<!-- 注册自动代理 -->
<aop:aspectj-autoproxy/>
</beans>
- 测试类
package com.caorui.test;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import com.caorui.service.SomeService;
import com.caorui.service.impl.SomeServiceImpl;
public class SomeTest {
//方式二:实现了测试类和service实现类的耦合
@Test
public void testSome01() {
//创建容器对象,ApplicationContext初始化时,所有容器中beans创建完毕
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
SomeService service = ac.getBean("someServiceImpl", SomeService.class);
service.doSome();
String result = service.doOther();
System.out.println(result);
}
}
2. 通知的用法(XML方式)
- 通知类
package com.caorui.aspects;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
//切面类
@Aspect //表明当前类是一个切面
public class MyAspect {
// //该注解表明当前方法是前置通知方法
// public void before() {
// System.out.println("前置方法执行!");
// }
//
// public void before(JoinPoint jp) {
// System.out.println("前置方法执行!" + jp);
// }
// //该注解表明当前方法是后置通知方法
// public void afterReturning(Object result) {
// System.out.println("后置方法执行!目标参数的返回值是:" + result);
// }
//
// //该注解表明当前方法是环绕通知方法
// public Object around(ProceedingJoinPoint pjp) throws Throwable {
// System.out.println("环绕通知:目标执行之前!");
// String result = (String)pjp.proceed();
// if (result != null) {
// result = result.toUpperCase();
// }
// System.out.println("环绕通知:目标执行之后!");
// return result;
// }
//
// //该注解表明当前方法是异常通知方法
// public void throwing(Exception ex) {
// System.out.println("异常通知方法执行!" + ex);
// }
//
//该注解表明当前方法是最终通知方法
public void after() {
System.out.println("最终通知方法执行!");
}
}
- 注册目标类、注册切面类、AOP配置
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 注册目标类 -->
<!-- bean的定义:以下配置相当于SomeService service = new SomeServiceImpl(); id相当于service这个引用 -->
<bean id="someServiceImpl" class="com.caorui.service.impl.SomeServiceImpl"></bean>
<!-- 注册切面,前置通知 -->
<bean id="MyAspect" class="com.caorui.aspects.MyAspect"></bean>
<!-- AOP配置 -->
<aop:config>
<!-- 定义切入点 -->
<aop:pointcut expression="execution(* *..service.*.doSome(..))" id="doSomePC"/>
<aop:pointcut expression="execution(* *..service.*.doOther(..))" id="doOtherPC"/>
<aop:aspect ref="MyAspect">
<!-- <aop:before method="before" pointcut-ref="doSomePC"/> -->
<!-- <aop:before method="before(org.aspectj.lang.JoinPoint)" pointcut-ref="doSomePC"/> -->
<!-- <aop:after-returning method="afterReturning(java.lang.Object)" pointcut-ref="doOtherPC" returning="result"/> result和方法的形参一致-->
<!-- <aop:around method="around" pointcut-ref="doOtherPC" /> -->
<!-- <aop:after-throwing method="throwing(java.lang.Exception)" pointcut-ref="doSomePC" throwing="ex"/> -->
<aop:after method="after" pointcut-ref="doSomePC"/>
</aop:aspect>
</aop:config>
</beans>