关于aop和自定义注解的知识点本文不做过多阐述,相关资料可去网上查看
这篇文章就讲解的很详细http://www.cnblogs.com/shipengzhi/articles/2716004.html
这里主要写的是个人在学习aop和自定义注解时做的一个小demo,主要实现自定义日志记录的功能。
1、在Maven中加入以下以依赖:
<properties>
<junit.version>4.12</junit.version>
<spring.version>4.1.3.RELEASE</spring.version>
</properties>
<dependencies>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- java编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
2、在applicationContext.xml中加入以下配置:
<?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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.annotation" ></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!-- 如果配置此项,所有注入的注解就可以使用了 -->
<context:annotation-config></context:annotation-config>
</beans>
3、编写自定义注解:
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @ interface MyLog {
int value() default 11;
}
点击这里 | 点击这里 |
---|---|
取值 | 描述 |
CONSTRUCTOR | 用于描述构造器(领盒饭)。 |
FIELD | 用于描述域(领盒饭)。 |
LOCAL_VARIABLE | 用于描述局部变量(领盒饭)。 |
METHOD | 用于描述方法。 |
PACKAGE | 用于描述包(领盒饭)。 |
PARAMETER | 用于描述参数。 |
TYPE | 用于描述类或接口(甚至 enum )。 |
@Retention 用于描述注解的生命周期(即:被描述的注解在什么范围内有效),其取值有:
点击这里 | 点击这里 |
---|---|
取值 | 描述 |
SOURCE | 在源文件中有效(即源文件保留,领盒饭)。 |
CLASS | 在 class 文件中有效(即 class 保留,领盒饭)。 |
RUNTIME | 在运行时有效(即运行时保留)。 |
@Documented 在默认的情况下javadoc命令不会将我们的annotation生成再doc中去的,所以使用该标记就是告诉jdk让它也将annotation生成到doc中去
@Inherited 比如有一个类A,在他上面有一个标记annotation,那么A的子类B不用再次标记annotation就可以继承使用。
4、编写接口和实现类:
public interface UserService {
public void addUser();
public void updateUser();
}
@Service("userService")
public class UserServiceImpl implements UserService {
@MyLog(value=110)//自定义注解
public void addUser() {
System.out.println("---->>>>>add user");
}
public void updateUser() {
System.out.println("----->>>>>update user");
}
}
5、编写切面:
@Aspect
@Component
public class MyAspect {
@Pointcut(value = "execution(* com.annotation.*.*(..))")
private void myPointCut() {
}
@Before("myPointCut() && @annotation(log)")
public void myBefore(JoinPoint joinPoint,MyApp log) {
System.out.println("前置通知 : " + joinPoint.getSignature().getName());
}
public void myAfterReturning(JoinPoint joinPoint, Object ret) {
System.out.println("后置通知 : " + ret);
}
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("前");
// 手动执行目标类
Object obj = joinPoint.proceed();
System.out.println("后");
return obj;
}
public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
System.out.println("抛出异常 : " + e.getMessage());
}
//该表达式指定com/annotation目录下及其所有子目录下的所有带有@MyLog注解的方法体为切点。
@After("myPointCut() && @annotation(log)")
public void myAfter(JoinPoint joinPoint,MyLog log) throws NoSuchMethodException,
SecurityException {
// System.out.println(log.value());
saveLog(log);
// printLog(joinPoint);
}
private void printLog(JoinPoint joinPoint) throws NoSuchMethodException,
SecurityException {
MyLog log = null;
Class targetClass = joinPoint.getTarget().getClass();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class[] parameterTypes = null;
if (arguments != null) {
int length = arguments.length;
parameterTypes = new Class[length];
for (int i = 0; i < length; ++i) {
parameterTypes[i] = arguments[i].getClass();
}
}
Method method = targetClass.getMethod(methodName, parameterTypes);
if (method != null) {
log = method.getAnnotation(MyLog.class);
}
if (log != null) {
System.out.println("====log======" + log.value());
if(log.value()==110){
System.out.println("日志注解中的值是110");
}
saveLog(log);
}
}
private void saveLog(MyLog log) {
System.out.println("插入日志记录");
System.out.println();
}
}
6、编写测试用例:
@org.junit.Test
public void demo1() {
String xmlPath="/com/annotation/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
UserService userService = (UserService) applicationContext
.getBean("userService");
userService.addUser();
userService.updateUser();
}
输出结果:
---->>>>>add user
插入日志记录
iam spect2
插入日志记录222
前置通知 : updateUser
----->>>>>update user
插入日志记录
iam spect2
插入日志记录222
前置通知 : updateUser
----->>>>>update user