Spring AOP中需要了解的几个概念
Advice通知类型:
前置通知:方法调用之前织入代码
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object obj = null;
System.out.println("前置通知");
obj = method.invoke(srcObj, args);
return obj;
}
后置通知: 方法调用之后织入代码
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object obj = null;
obj = method.invoke(srcObj, args);
System.out.println("后置通知");
return obj;
}
异常通知:方法异常时织入的代码
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object obj = null;
try{
obj = method.invoke(srcObj, args);
}catch(Exception e){
System.out.println("例外通知");
}
return obj;
}
最终通知:在finally块处织入代码
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object obj = null;
try{
obj = method.invoke(srcObj, args);
}finally{
System.out.println("最终通知");
}
return obj;
}
环绕通知: 即在进入方法的前后进行通知(前置和后置的结合体)
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object obj = null;
try{
System.out.println("环绕通知:进入方法");
obj = method.invoke(srcObj, args);
System.out.println("环绕通知:退出方法");
}catch(Exception e){
System.out.println("例外通知");
}finally{
System.out.println("最终通知");
}
return obj;
}
使用Spring进行面向切面(AOP)编程
要进行AOP编程,首先我们要在Spring的配置文件中引入aop命名空间(红色部分)
<?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:context="http://www.springframework.org/schema/context"
[color=red]xmlns:aop="http://www.springframework.org/schema/aop"[/color]
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
[color=red]http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd[/color]">
<context:component-scan base-package="com.wdpc.aop" />
<aop:aspectj-autoproxy />
</beans>
Spring中提供了两种方式进行AOP的配置,
1. XML配置
2. 注释
先来看注释方式:
红色部分是在命名空间中加入Spring对AOP的支持
<aop:aspectj-autoproxy /> 是打开AOP注释方式的开关
首先我们定义一个业务层的类
接口:
public interface UserService {
public void create() throws Exception;
public void update() throws Exception;
public void delete() throws Exception;
}
实现类:
public class UserServiceImpl implements UserService {
public void create() throws Exception {
System.out.println("create方法调用");
}
public void delete() throws Exception {
System.out.println("delete方法调用");
}
public void update() throws Exception {
System.out.println("update方法调用");
}
}
声明一个切面
Aspect切面: 即我们抽取出来的公共代码组成的类,里面有很多方法
任意带有一个@Aspect切面(拥有@Aspect注解)的bean都将被Spring自动识别并用于配置Spring AOP
@Aspect
@Component
public class MyInterceptor {
@Before("execution(* com.wdpc.aop..*.*(..))")
public void beforeAdvice() {
System.out.println("前置通知");
}
@AfterReturning("execution(* com.wdpc.aop..*.*(..))")
public void AfterAdvice() {
System.out.println("后置通知");
}
@AfterThrowing("execution(* com.wdpc.aop..*.*(..))")
public void throwAdvice() {
System.out.println("异常通知");
}
@After("execution(* com.wdpc.aop..*.*(..))")
public void finallyAdvice() {
System.out.println("最终通知");
}
@Around("execution(* com.wdpc.aop..*.*(..))")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知:进入方法");
Object retVal = pjp.proceed();
System.out.println("环绕通知:退出方法");
return retVal;
}
}
注意的地方: MyInterceptor这个类一定要纳入Spring的管理范围,所以我们通过注释语法将其纳入Spring的管理范围
切入点(Pointcut):一个正则表达式, 表示当执行某个特定名称的方法, 可以理解为 原始类中的业务方法名
利用切入点来简化切面的编写:
@Aspect
@Component
public class MyInterceptor {
@Pointcut("execution(* com.wdpc.aop..*.*(..))")
private void anyMethod(){}
@Before("anyMethod()")
public void beforeAdvice() {
System.out.println("前置通知");
}
@AfterReturning("anyMethod()")
public void AfterAdvice() {
System.out.println("后置通知");
}
@AfterThrowing("anyMethod()")
public void throwAdvice() {
System.out.println("异常通知");
}
@After("anyMethod()")
public void finallyAdvice() {
System.out.println("最终通知");
}
@Around("anyMethod()")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知:进入方法");
Object retVal = pjp.proceed();
System.out.println("环绕通知:退出方法");
return retVal;
}
}
@Pointcut("execution(* com.wdpc.aop..*.*(..))")
private void anyMethod(){}
以上两行代码定义的就是一个切入点
* :代表所有的返回类型
com.wdpc.aop.. :代表com.wdpc.aop包下的所有包与子包
*.*(..) :代表所有类的所有方法
在切面中获取方法参数
在接口中添加一个方法,并在实现中类实现:
接口:
public void argsMethod(String name) throws Exception;
实现类:
public void argsMethod(String name) throws Exception {
System.out.println("argsMethod方法调用");
}
为了演示方便,我们生成一个新的切面类:
public class MyInterceptor {
@Pointcut("execution(* com.wdpc.aop.service.impl.UserServiceImpl.argsMethod(..))")
private void argsMethod(){}
@Before("argsMethod() && args(name)")
public void beforeAdvice(String name) {
System.out.println("前置通知:" + name);
}
}
Test:
public class Test {
public static void main(String[] args){
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) ctx.getBean("userService");
try {
userService.argsMethod("wdpc");
} catch (Exception e) {
}
}
}
在切面中获取方法的返回结果
在接口中添加一个方法,并在实现类中实现:
接口:
public String resultMethod(String name) throws Exception
实现类:
public String resultMethod(String name) throws Exception {
System.out.println("resultMethod方法调用");
return "我的名字:" + name;
}
为了演示方便,我们生成一个新的切面类:
@Aspect
@Component
public class MyInterceptor {
@Pointcut("execution(* com.wdpc.aop.service.impl.UserServiceImpl.resultMethod(..))")
private void argsMethod() {
}
@AfterReturning(pointcut="argsMethod()", returning = "name")
public void AfterAdvice(String name) {
System.out.println("后置通知:" + name);
}
}
语法上需要注意一点:
显示指定切入点: pointcut="argsMethod()",
指定返回值: returning = "name", name必须和参数名一样
Test:
public class Test {
public static void main(String[] args){
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) ctx.getBean("userService");
try {
userService.resultMethod("wdpc");
} catch (Exception e) {
}
}
}
在切面中得到异常对象
在接口中添加一个方法,并在实现类中实现:
接口:
public void getException() throws Exception;
实现:
public void getException() throws Exception {
System.out.println("getException方法调用");
throw new Exception("得到异常对象");
}
为了演示方便,我们生成一个新的切面类:
@Aspect
@Component
public class MyInterceptor {
@Pointcut("execution(* com.wdpc.aop.service.impl.UserServiceImpl.getException(..))")
private void argsMethod() {
}
@AfterThrowing(pointcut = "argsMethod()", throwing = "e")
public void throwAdvice(Exception e) {
System.out.println("异常通知:" + e);
}
}
Test:
public class Test {
public static void main(String[] args){
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) ctx.getBean("userService");
try {
userService.getException();
} catch (Exception e) {
}
}
}
在使用Spring AOP时,需要注意的地方就是切入点正则表达式的编写
@Pointcut("execution(* com.wdpc.aop.service.impl.UserServiceImpl.getException(..))")
下面列举一些示例:
任意公共方法的执行:
execution(public * *(..))
任何一个名字以“set”开始的方法的执行:
execution(* set*(..))
AccountService接口定义的任意方法的执行:
execution(* com.xyz.service.AccountService.*(..))
在service包中定义的任意方法的执行:
execution(* com.xyz.service.*.*(..))
在service包或其子包中定义的任意方法的执行:
execution(* com.xyz.service..*.*(..))
Advice通知类型:
前置通知:方法调用之前织入代码
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object obj = null;
System.out.println("前置通知");
obj = method.invoke(srcObj, args);
return obj;
}
后置通知: 方法调用之后织入代码
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object obj = null;
obj = method.invoke(srcObj, args);
System.out.println("后置通知");
return obj;
}
异常通知:方法异常时织入的代码
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object obj = null;
try{
obj = method.invoke(srcObj, args);
}catch(Exception e){
System.out.println("例外通知");
}
return obj;
}
最终通知:在finally块处织入代码
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object obj = null;
try{
obj = method.invoke(srcObj, args);
}finally{
System.out.println("最终通知");
}
return obj;
}
环绕通知: 即在进入方法的前后进行通知(前置和后置的结合体)
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object obj = null;
try{
System.out.println("环绕通知:进入方法");
obj = method.invoke(srcObj, args);
System.out.println("环绕通知:退出方法");
}catch(Exception e){
System.out.println("例外通知");
}finally{
System.out.println("最终通知");
}
return obj;
}
使用Spring进行面向切面(AOP)编程
要进行AOP编程,首先我们要在Spring的配置文件中引入aop命名空间(红色部分)
<?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:context="http://www.springframework.org/schema/context"
[color=red]xmlns:aop="http://www.springframework.org/schema/aop"[/color]
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
[color=red]http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd[/color]">
<context:component-scan base-package="com.wdpc.aop" />
<aop:aspectj-autoproxy />
</beans>
Spring中提供了两种方式进行AOP的配置,
1. XML配置
2. 注释
先来看注释方式:
红色部分是在命名空间中加入Spring对AOP的支持
<aop:aspectj-autoproxy /> 是打开AOP注释方式的开关
首先我们定义一个业务层的类
接口:
public interface UserService {
public void create() throws Exception;
public void update() throws Exception;
public void delete() throws Exception;
}
实现类:
public class UserServiceImpl implements UserService {
public void create() throws Exception {
System.out.println("create方法调用");
}
public void delete() throws Exception {
System.out.println("delete方法调用");
}
public void update() throws Exception {
System.out.println("update方法调用");
}
}
声明一个切面
Aspect切面: 即我们抽取出来的公共代码组成的类,里面有很多方法
任意带有一个@Aspect切面(拥有@Aspect注解)的bean都将被Spring自动识别并用于配置Spring AOP
@Aspect
@Component
public class MyInterceptor {
@Before("execution(* com.wdpc.aop..*.*(..))")
public void beforeAdvice() {
System.out.println("前置通知");
}
@AfterReturning("execution(* com.wdpc.aop..*.*(..))")
public void AfterAdvice() {
System.out.println("后置通知");
}
@AfterThrowing("execution(* com.wdpc.aop..*.*(..))")
public void throwAdvice() {
System.out.println("异常通知");
}
@After("execution(* com.wdpc.aop..*.*(..))")
public void finallyAdvice() {
System.out.println("最终通知");
}
@Around("execution(* com.wdpc.aop..*.*(..))")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知:进入方法");
Object retVal = pjp.proceed();
System.out.println("环绕通知:退出方法");
return retVal;
}
}
注意的地方: MyInterceptor这个类一定要纳入Spring的管理范围,所以我们通过注释语法将其纳入Spring的管理范围
切入点(Pointcut):一个正则表达式, 表示当执行某个特定名称的方法, 可以理解为 原始类中的业务方法名
利用切入点来简化切面的编写:
@Aspect
@Component
public class MyInterceptor {
@Pointcut("execution(* com.wdpc.aop..*.*(..))")
private void anyMethod(){}
@Before("anyMethod()")
public void beforeAdvice() {
System.out.println("前置通知");
}
@AfterReturning("anyMethod()")
public void AfterAdvice() {
System.out.println("后置通知");
}
@AfterThrowing("anyMethod()")
public void throwAdvice() {
System.out.println("异常通知");
}
@After("anyMethod()")
public void finallyAdvice() {
System.out.println("最终通知");
}
@Around("anyMethod()")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知:进入方法");
Object retVal = pjp.proceed();
System.out.println("环绕通知:退出方法");
return retVal;
}
}
@Pointcut("execution(* com.wdpc.aop..*.*(..))")
private void anyMethod(){}
以上两行代码定义的就是一个切入点
* :代表所有的返回类型
com.wdpc.aop.. :代表com.wdpc.aop包下的所有包与子包
*.*(..) :代表所有类的所有方法
在切面中获取方法参数
在接口中添加一个方法,并在实现中类实现:
接口:
public void argsMethod(String name) throws Exception;
实现类:
public void argsMethod(String name) throws Exception {
System.out.println("argsMethod方法调用");
}
为了演示方便,我们生成一个新的切面类:
public class MyInterceptor {
@Pointcut("execution(* com.wdpc.aop.service.impl.UserServiceImpl.argsMethod(..))")
private void argsMethod(){}
@Before("argsMethod() && args(name)")
public void beforeAdvice(String name) {
System.out.println("前置通知:" + name);
}
}
Test:
public class Test {
public static void main(String[] args){
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) ctx.getBean("userService");
try {
userService.argsMethod("wdpc");
} catch (Exception e) {
}
}
}
在切面中获取方法的返回结果
在接口中添加一个方法,并在实现类中实现:
接口:
public String resultMethod(String name) throws Exception
实现类:
public String resultMethod(String name) throws Exception {
System.out.println("resultMethod方法调用");
return "我的名字:" + name;
}
为了演示方便,我们生成一个新的切面类:
@Aspect
@Component
public class MyInterceptor {
@Pointcut("execution(* com.wdpc.aop.service.impl.UserServiceImpl.resultMethod(..))")
private void argsMethod() {
}
@AfterReturning(pointcut="argsMethod()", returning = "name")
public void AfterAdvice(String name) {
System.out.println("后置通知:" + name);
}
}
语法上需要注意一点:
显示指定切入点: pointcut="argsMethod()",
指定返回值: returning = "name", name必须和参数名一样
Test:
public class Test {
public static void main(String[] args){
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) ctx.getBean("userService");
try {
userService.resultMethod("wdpc");
} catch (Exception e) {
}
}
}
在切面中得到异常对象
在接口中添加一个方法,并在实现类中实现:
接口:
public void getException() throws Exception;
实现:
public void getException() throws Exception {
System.out.println("getException方法调用");
throw new Exception("得到异常对象");
}
为了演示方便,我们生成一个新的切面类:
@Aspect
@Component
public class MyInterceptor {
@Pointcut("execution(* com.wdpc.aop.service.impl.UserServiceImpl.getException(..))")
private void argsMethod() {
}
@AfterThrowing(pointcut = "argsMethod()", throwing = "e")
public void throwAdvice(Exception e) {
System.out.println("异常通知:" + e);
}
}
Test:
public class Test {
public static void main(String[] args){
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) ctx.getBean("userService");
try {
userService.getException();
} catch (Exception e) {
}
}
}
在使用Spring AOP时,需要注意的地方就是切入点正则表达式的编写
@Pointcut("execution(* com.wdpc.aop.service.impl.UserServiceImpl.getException(..))")
下面列举一些示例:
任意公共方法的执行:
execution(public * *(..))
任何一个名字以“set”开始的方法的执行:
execution(* set*(..))
AccountService接口定义的任意方法的执行:
execution(* com.xyz.service.AccountService.*(..))
在service包中定义的任意方法的执行:
execution(* com.xyz.service.*.*(..))
在service包或其子包中定义的任意方法的执行:
execution(* com.xyz.service..*.*(..))