Spring提供了两种切面使用方式,实际工作中使用其一就可以:
(1)、基于XML配置方式进行AOP开发
(2)、基于注解方式进行AOP开发
1、新建项目,引入必要jar文件
2、在配置文件中引入aop命名空间,启动对@AspectJ注解的支持:
<?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"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<aop:aspectj-autoproxy/>
</beans>
3、创建业务bean,供测试使用:
package com.wxy.service;
public interface PeopleService {
public void save(String name);
public void update(String name, Integer id);
public String getPeopleName(Integer id);
}
----------------------------------------------------------------
package com.wxy.service.impl;
import com.wxy.service.PeopleService;
public class PeopleServiceBean implements PeopleService {
@Override
public String getPeopleName(Integer id) {
System.out.println(" 我是getPeopleName(Integer id)方法");
return "wxy";
}
@Override
public void save(String name) {
System.out.println(" 我是save(String name)方法");
}
@Override
public void update(String name, Integer id) {
System.out.println(" 我是update(String name, Integer id)方法");
}
}
在beans.xml中配置,将bean交给spring容器管理:
………
<aop:aspectj-autuproxy/>
<bean id="peopleService" class="com.wxy.service.impl.PeopleServiceBean"/>
</beans>
4、定义切面:
package com.wxy.service;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* 基于注解方式申明切面
* 用来定义我们要拦截的方法
*/
@Aspect
public class MyInterceptor {
/**
* 切入点定义
* com.wxy.service.impl.PeopleServiceBean该类的所有方法将被拦截
*/
@Pointcut("execution(* com.wxy.service.impl.PeopleServiceBean.*(..))")
private void anyMethod() {
}
/**
* 前置通知
* 拦截到方法,在方法执行前,先执行前置通知
* @param userName
*/
@Before("anyMethod()")
public void doAccessCheck(String userName) {
System.out.println("前置通知");
}
}
在配置文件beans.xml中配置切面,交给spring来管理:
……….
<bean id="myIntercepetor" class="com.wxy.service.MyInterceptor"/>
</beans>
5、 开发客户端调用业务端bean,测试切面的拦截机制:
public class SpringAOPTest {
public static void main(String[] args) {
ApplicationContext cxt = new ClassPathXmlApplicationContext("beans.xml");
PeopleService peopleService = (PeopleService) cxt.getBean("peopleService");
peopleService.save("wxy");
}
}
测试结果:
2011-8-23 22:25:09 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@15eb0a9: display name [org.springframework.context.support.ClassPathXmlApplicationContext@15eb0a9]; startup date [Tue Aug 23 22:25:09 CST 2011]; root of context hierarchy
2011-8-23 22:25:09 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [beans.xml]
2011-8-23 22:25:09 org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
信息: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@15eb0a9]: org.springframework.beans.factory.support.DefaultListableBeanFactory@e2dae9
2011-8-23 22:25:09 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@e2dae9: defining beans [org.springframework.aop.config.internalAutoProxyCreator,myInterceptor,peopleService]; root of factory hierarchy
前置通知:wxy
我是save()方法
使用Spring的注解方式实现AOP的细节 :
1、修改切面类,增加其他通知注解:
package com.wxy.service;
/**
* 切面
*
*/
@Aspect
public class MyInterceptor {
@Pointcut("execution (* com.wxy.service.impl.PeopleServiceBean.*(..))")
private void anyMethod() {
}//声明一个切入点
@Before("anyMethod() && args(name)")
public void doAccessCheck(String name) {
System.out.println("前置通知:" + name);
}
@AfterReturning(pointcut = "anyMethod()", returning = "result")
public void doAfterReturning(String result) {
System.out.println("后置通知:" + result);
}
@After("anyMethod()")
public void doAfter() {
System.out.println("最终通知");
}
@AfterThrowing(pointcut = "anyMethod()", throwing = "e")
public void doAfterThrowing(Exception e) {
System.out.println("例外通知:" + e);
}
@Around("anyMethod()")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
//if(){//判断用户是否在权限
System.out.println("进入方法");
Object result = pjp.proceed();
System.out.println("退出方法");
//}
return result;
}
}
PeopleServiceBean修改,添加例外代码段:
package com.wxy.service.impl;
import com.wxy.service.PeopleService;
public class PeopleServiceBean implements PeopleService {
public String getPersonName(Integer id) {
System.out.println("我是getPersonName()方法");
return "xxx";
}
public void save(String name) {
throw new RuntimeException("这是个美丽的例外");
//System.out.println("我是save()方法");
}
public void update(String name, Integer id) {
System.out.println("我是update()方法");
}
}
重新运行测试类,测试结果:
2011-8-23 22:37:30 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@15eb0a9: display name [org.springframework.context.support.ClassPathXmlApplicationContext@15eb0a9]; startup date [Tue Aug 23 22:37:30 CST 2011]; root of context hierarchy
2011-8-23 22:37:30 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [beans.xml]
2011-8-23 22:37:30 org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
信息: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@15eb0a9]: org.springframework.beans.factory.support.DefaultListableBeanFactory@e2dae9
2011-8-23 22:37:30 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@e2dae9: defining beans [org.springframework.aop.config.internalAutoProxyCreator,myInterceptor,peopleService]; root of factory hierarchy
前置通知:wxy
进入方法
最终通知
例外通知:java.lang.RuntimeException: 这是个美丽的例外
Exception in thread "main" java.lang.RuntimeException: 这是个美丽的例外
at com.wxy.service.impl.PeopleServiceBean.save(PeopleServiceBean.java:13)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:307)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:50)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:42)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:54)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:77)
at com.wxy.service.MyInterceptor.doBasicProfiling(MyInterceptor.java:46)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:627)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:616)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:64)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:50)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:160)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy10.save(Unknown Source)
at com.wxy.test.SpringAOPTest.main(SpringAOPTest.java:14)
Tips:
spring aop 切点表达式配置pointcut execution
Spring AOP 用户可能会经常使用 execution pointcut designator。执行表达式的格式如下:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
除了返回类型模式(上面代码片断中的ret-type-pattern),名字模式和参数模式以外,所有的部分都是可选的。 返回类型模式决定了方法的返回类型必须依次匹配一个连接点。你会使用的最频繁的返回类型模式是 * ,它代表了匹配任意的返回类型。 一个全称限定的类型名将只会匹配返回给定类型的方法。名字模式匹配的是方法名。你可以使用 * 通配符作为所有或者部分命名模式。 参数模式稍微有点复杂:() 匹配了一个不接受任何参数的方法, 而 (..) 匹配了一个接受任意数量参数的方法(零或者更多)。模式 (*) 匹配了一个接受一个任何类型的参数的方法。 模式 (*,String) 匹配了一个接受两个参数的方法,第一个可以是任意类型,第二个则必须是String类型。
下面给出一些常见切入点表达式的例子。
任意公共方法的执行:
execution(public * *(..))
任何一个以“set”开始的方法的执行:
execution(* set*(..))
AccountService 接口的任意方法的执行:
execution(* com.xyz.service.AccountService.*(..))
定义在service包里的任意方法的执行:
execution(* com.xyz.service.*.*(..))
定义在service包或者子包里的任意方法的执行:
execution(* com.xyz.service..*.*(..))