第一,注解:
@Before – 目标方法执行前执行
@After – 目标方法执行后执行(不管有误异常都会执行)
@AfterReturning – 目标方法返回后执行,如果发生异常不执行(即成功执行后才会执行)
@AfterThrowing – 异常时执行
@Around – 在执行上面其他操作的同时也执行这个方法
第二,SpringMVC如果要使用AOP注解,必须将
1
|
<
aop:aspectj-autoproxy
proxy-target-class
=
"true"
/>
|
放在spring-servlet.xml(配置MVC的XML)中!
第三,execution表达式请参考Spring官网http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html
代码下载:http://pan.baidu.com/s/1gdeopW3
首先是Maven依赖:
<
properties
>
<
springframework
>4.0.5.RELEASE</
springframework
>
<
aspectj
>1.8.5</
aspectj
>
<
servlet
>3.1.0</
servlet
>
</
properties
>
<
dependencies
>
<!-- servlet -->
<
dependency
>
<
groupId
>javax.servlet</
groupId
>
<
artifactId
>javax.servlet-api</
artifactId
>
<
version
>${servlet}</
version
>
<
scope
>compile</
scope
>
</
dependency
>
<!-- Spring web mvc -->
<
dependency
>
<
groupId
>org.springframework</
groupId
>
<
artifactId
>spring-webmvc</
artifactId
>
<
version
>${springframework}</
version
>
</
dependency
>
<!-- Spring AOP -->
<
dependency
>
<
groupId
>org.springframework</
groupId
>
<
artifactId
>spring-aop</
artifactId
>
<
version
>${springframework}</
version
>
</
dependency
>
<
dependency
>
<
groupId
>org.aspectj</
groupId
>
<
artifactId
>aspectjrt</
artifactId
>
<
version
>${aspectj}</
version
>
</
dependency
>
<
dependency
>
<
groupId
>org.aspectj</
groupId
>
<
artifactId
>aspectjweaver</
artifactId
>
<
version
>${aspectj}</
version
>
</
dependency
>
</
dependencies
>
spring-context.xml配置,基本无内容
<!-- 配置扫描路径 -->
<
context:component-scan
base-package
=
"org.xdemo.example.springaop"
>
<
context:exclude-filter
type
=
"annotation"
expression
=
"org.springframework.stereotype.Controller"
/>
</
context:component-scan
>
spring-mvc.xml配置
<!-- 最重要!!!如果放在spring-context.xml中,这里的aop设置将不会生效 -->
<
aop:aspectj-autoproxy
proxy-target-class
=
"true"
/>
<!-- 启用MVC注解 -->
<
mvc:annotation-driven
/>
<!-- 指定Sping组件扫描的基本包路径 -->
<
context:component-scan
base-package
=
"org.xdemo.example.springaop"
>
<
context:include-filter
type
=
"annotation"
expression
=
"org.springframework.stereotype.Controller"
/>
</
context:component-scan
>
Web.xml配置
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<
web-app
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xmlns
=
"http://java.sun.com/xml/ns/javaee"
xmlns:web
=
"http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
xsi:schemaLocation
=
"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version
=
"3.0"
>
<
display-name
>Archetype Created Web Application</
display-name
>
<!-- WebAppRootKey -->
<
context-param
>
<
param-name
>webAppRootKey</
param-name
>
<
param-value
>org.xdemo.example.springaop</
param-value
>
</
context-param
>
<!-- Spring Context -->
<
context-param
>
<
param-name
>contextConfigLocation</
param-name
>
<
param-value
>classpath:spring-context.xml</
param-value
>
</
context-param
>
<
listener
>
<
listener-class
>org.springframework.web.context.ContextLoaderListener</
listener-class
>
</
listener
>
<!-- SpringMVC -->
<
servlet
>
<
servlet-name
>SpringMVC</
servlet-name
>
<
servlet-class
>org.springframework.web.servlet.DispatcherServlet</
servlet-class
>
<
init-param
>
<
param-name
>contextConfigLocation</
param-name
>
<
param-value
>classpath:spring-mvc.xml</
param-value
>
</
init-param
>
<
load-on-startup
>1</
load-on-startup
>
</
servlet
>
<
servlet-mapping
>
<
servlet-name
>SpringMVC</
servlet-name
>
<
url-pattern
>/</
url-pattern
>
</
servlet-mapping
>
</
web-app
>
注解Log
package
org.xdemo.example.springaop.annotation;
import
java.lang.annotation.ElementType;
import
java.lang.annotation.Retention;
import
java.lang.annotation.RetentionPolicy;
import
java.lang.annotation.Target;
@Retention
(RetentionPolicy.RUNTIME)
@Target
({ ElementType.METHOD })
public
@interface
Log {
String name()
default
""
;
}
日志AOP,写法一LogAop_1
package
org.xdemo.example.springaop.aop;
import
java.lang.reflect.Method;
import
java.util.UUID;
import
org.aspectj.lang.JoinPoint;
import
org.aspectj.lang.ProceedingJoinPoint;
import
org.aspectj.lang.annotation.After;
import
org.aspectj.lang.annotation.Around;
import
org.aspectj.lang.annotation.Aspect;
import
org.aspectj.lang.annotation.Before;
import
org.aspectj.lang.reflect.MethodSignature;
import
org.springframework.stereotype.Component;
import
org.xdemo.example.springaop.annotation.Log;
@Aspect
@Component
public
class
LogAop_1 {
ThreadLocal<Long> time=
new
ThreadLocal<Long>();
ThreadLocal<String> tag=
new
ThreadLocal<String>();
/**
* 在所有标注@Log的地方切入
* @param joinPoint
*/
@Before
(
"@annotation(org.xdemo.example.springaop.annotation.Log)"
)
public
void
beforeExec(JoinPoint joinPoint){
time.set(System.currentTimeMillis());
tag.set(UUID.randomUUID().toString());
info(joinPoint);
MethodSignature ms=(MethodSignature) joinPoint.getSignature();
Method method=ms.getMethod();
System.out.println(method.getAnnotation(Log.
class
).name()+
"标记"
+tag.get());
}
@After
(
"@annotation(org.xdemo.example.springaop.annotation.Log)"
)
public
void
afterExec(JoinPoint joinPoint){
MethodSignature ms=(MethodSignature) joinPoint.getSignature();
Method method=ms.getMethod();
System.out.println(
"标记为"
+tag.get()+
"的方法"
+method.getName()+
"运行消耗"
+(System.currentTimeMillis()-time.get())+
"ms"
);
}
@Around
(
"@annotation(org.xdemo.example.springaop.annotation.Log)"
)
public
void
aroundExec(ProceedingJoinPoint pjp)
throws
Throwable{
System.out.println(
"我是Around,来打酱油的"
);
pjp.proceed();
}
private
void
info(JoinPoint joinPoint){
System.out.println(
"--------------------------------------------------"
);
System.out.println(
"King:\t"
+joinPoint.getKind());
System.out.println(
"Target:\t"
+joinPoint.getTarget().toString());
Object[] os=joinPoint.getArgs();
System.out.println(
"Args:"
);
for
(
int
i=
0
;i<os.length;i++){
System.out.println(
"\t==>参数["
+i+
"]:\t"
+os[i].toString());
}
System.out.println(
"Signature:\t"
+joinPoint.getSignature());
System.out.println(
"SourceLocation:\t"
+joinPoint.getSourceLocation());
System.out.println(
"StaticPart:\t"
+joinPoint.getStaticPart());
System.out.println(
"--------------------------------------------------"
);
}
}
日志AOP,写法二LogAop_2
package
org.xdemo.example.springaop.aop;
import
java.lang.reflect.Method;
import
java.util.UUID;
import
org.aspectj.lang.JoinPoint;
import
org.aspectj.lang.ProceedingJoinPoint;
import
org.aspectj.lang.annotation.After;
import
org.aspectj.lang.annotation.Around;
import
org.aspectj.lang.annotation.Aspect;
import
org.aspectj.lang.annotation.Before;
import
org.aspectj.lang.annotation.Pointcut;
import
org.aspectj.lang.reflect.MethodSignature;
import
org.springframework.stereotype.Component;
import
org.xdemo.example.springaop.annotation.Log;
@Aspect
@Component
public
class
LogAop_2 {
ThreadLocal<Long> time=
new
ThreadLocal<Long>();
ThreadLocal<String> tag=
new
ThreadLocal<String>();
@Pointcut
(
"@annotation(org.xdemo.example.springaop.annotation.Log)"
)
public
void
log(){
System.out.println(
"我是一个切入点"
);
}
/**
* 在所有标注@Log的地方切入
* @param joinPoint
*/
@Before
(
"log()"
)
public
void
beforeExec(JoinPoint joinPoint){
time.set(System.currentTimeMillis());
tag.set(UUID.randomUUID().toString());
info(joinPoint);
MethodSignature ms=(MethodSignature) joinPoint.getSignature();
Method method=ms.getMethod();
System.out.println(method.getAnnotation(Log.
class
).name()+
"标记"
+tag.get());
}
@After
(
"log()"
)
public
void
afterExec(JoinPoint joinPoint){
MethodSignature ms=(MethodSignature) joinPoint.getSignature();
Method method=ms.getMethod();
System.out.println(
"标记为"
+tag.get()+
"的方法"
+method.getName()+
"运行消耗"
+(System.currentTimeMillis()-time.get())+
"ms"
);
}
@Around
(
"log()"
)
public
void
aroundExec(ProceedingJoinPoint pjp)
throws
Throwable{
System.out.println(
"我是Around,来打酱油的"
);
pjp.proceed();
}
private
void
info(JoinPoint joinPoint){
System.out.println(
"--------------------------------------------------"
);
System.out.println(
"King:\t"
+joinPoint.getKind());
System.out.println(
"Target:\t"
+joinPoint.getTarget().toString());
Object[] os=joinPoint.getArgs();
System.out.println(
"Args:"
);
for
(
int
i=
0
;i<os.length;i++){
System.out.println(
"\t==>参数["
+i+
"]:\t"
+os[i].toString());
}
System.out.println(
"Signature:\t"
+joinPoint.getSignature());
System.out.println(
"SourceLocation:\t"
+joinPoint.getSourceLocation());
System.out.println(
"StaticPart:\t"
+joinPoint.getStaticPart());
System.out.println(
"--------------------------------------------------"
);
}
}
用到的一个用户类User
package
org.xdemo.example.springaop.bean;
public
class
User {
private
String name;
public
String getName() {
return
name;
}
public
void
setName(String name) {
this
.name = name;
}
}
一个测试的Controller
package
org.xdemo.example.springaop.controller;
import
javax.annotation.Resource;
import
org.springframework.stereotype.Controller;
import
org.springframework.web.bind.annotation.RequestMapping;
import
org.springframework.web.bind.annotation.ResponseBody;
import
org.xdemo.example.springaop.annotation.Log;
import
org.xdemo.example.springaop.bean.User;
import
org.xdemo.example.springaop.service.IUserService;
@Controller
@RequestMapping
(
"/aop"
)
public
class
SpringController {
@Resource
IUserService userService;
@Log
(name=
"您访问了aop1方法"
)
@ResponseBody
@RequestMapping
(value=
"aop1"
)
public
String aop1(){
return
"AOP"
;
}
@Log
(name=
"您访问了aop2方法"
)
@ResponseBody
@RequestMapping
(value=
"aop2"
)
public
String aop2(String string)
throws
InterruptedException{
Thread.sleep(1000L);
User user=
new
User();
user.setName(string);
userService.save(user);
return
string;
}
}
一个测试的接口实现类(接口类略)
package
org.xdemo.example.springaop.service;
import
org.springframework.stereotype.Service;
import
org.xdemo.example.springaop.annotation.Log;
import
org.xdemo.example.springaop.bean.User;
@Service
public
class
UserServiceImpl
implements
IUserService {
@Log
(name =
"您访问了保存用户信息"
)
public
void
save(User user) {
System.out.println(user.getName());
}
}
在地址栏输入地址测试:http://localhost:8080/springaop/aop/aop2?string=sxxxxx