先定一个注解,用于在Controller方法上记录每个方法的用途。
-
package com.zjf.spring.annotation;
-
import java.lang.annotation.Documented;
-
import java.lang.annotation.ElementType;
-
import java.lang.annotation.Retention;
-
import java.lang.annotation.RetentionPolicy;
-
import java.lang.annotation.Target;
-
-
/**
-
* 定义注解
-
*
-
@Target : 用来说明该注解可以被声明在那些元素之前。
-
-
ElementType.TYPE:说明该注解只能被声明在一个类前。
-
-
ElementType.FIELD:说明该注解只能被声明在一个类的字段前。
-
-
ElementType.METHOD:说明该注解只能被声明在一个类的方法前。
-
-
ElementType.PARAMETER:说明该注解只能被声明在一个方法参数前。
-
-
ElementType.CONSTRUCTOR:说明该注解只能声明在一个类的构造方法前。
-
-
ElementType.LOCAL_VARIABLE:说明该注解只能声明在一个局部变量前。
-
-
ElementType.ANNOTATION_TYPE:说明该注解只能声明在一个注解类型前。
-
-
ElementType.PACKAGE:说明该注解只能声明在一个包名前。
-
*/
-
@Target({ElementType.METHOD})
-
-
-
/**
-
@Retention :用来说明该注解类的生命周期。它有以下三个参数:
-
-
RetentionPolicy.SOURCE : 注解只保留在源文件中
-
-
RetentionPolicy.CLASS : 注解保留在class文件中,在加载到JVM虚拟机时丢弃
-
-
RetentionPolicy.RUNTIME : 注解保留在程序运行期间,此时可以通过反射获得定义在某个类上的所有注解。
-
*/
-
@Retention(RetentionPolicy.RUNTIME)
-
/**
-
Annotation(注解)是JDK5.0及以后版本引入的。它可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查。
-
注解是以'@注解名'在代码中存在的,根据注解参数的个数,我们可以将注解分为:标记注解、单值注解、完整注解三类。
-
它们都不会直接影响到程序的语义,只是作为注解(标识)存在,我们可以通过反射机制编程实现对这些元数据(用来描述数据的数据)的访问。
-
另外,你可以在编译时选择代码里的注解是否只存在于源代码级,或者它也能在class文件中出现。
-
*/
-
/*
-
* 注解名字 LogAnnotation
-
*/
-
public @interface LogAnnotation {
-
//为LogAnnotation定义了一个desc属性 用于描述方法的description 在记录甚至日志的时候获取
-
String desc() default "无描述信息";
-
}
定义切面:
-
package com.zjf.spring.log;
-
-
import java.lang.reflect.Method;
-
-
import javax.servlet.http.HttpServletRequest;
-
-
-
-
import org.aspectj.lang.JoinPoint;
-
import org.aspectj.lang.Signature;
-
import org.aspectj.lang.annotation.AfterReturning;
-
import org.aspectj.lang.annotation.AfterThrowing;
-
import org.aspectj.lang.annotation.Aspect;
-
import org.aspectj.lang.annotation.Pointcut;
-
import org.aspectj.lang.reflect.MethodSignature;
-
import org.slf4j.Logger;
-
import org.slf4j.LoggerFactory;
-
import org.springframework.stereotype.Component;
-
import org.springframework.web.context.request.RequestContextHolder;
-
import org.springframework.web.context.request.ServletRequestAttributes;
-
-
import com.zjf.spring.annotation.LogAnnotation;
-
-
/**
-
*
-
* @Aspect生命这个类是一个切面
-
*
-
*/
-
@Aspect
-
@Component
-
public class SystemLogAspect {
-
// 注入Service用于把日志保存数据库
-
-
// 本地异常日志记录对象
-
private static final Logger logger = LoggerFactory
-
.getLogger(SystemLogAspect.class);
-
-
// Controller层切点 通过注解进行切点 凡是生命了LogAnnotation注解的方法都要进入这个切面
-
@Pointcut("@annotation(com.zjf.spring.annotation.LogAnnotation)")
-
public void controllerAspect() {
-
-
}
-
-
/**
-
*
-
* 方法操作成功 会进入@AfterReturning
-
* @param joinPoint 代表会记录切点的信息 就是代码运行到切点是的变量环境
-
* 可以从joinPoint获取使用的LogAnnotation信息
-
* 切点
-
*/
-
@AfterReturning(pointcut = "controllerAspect()")
-
public void doBefore(JoinPoint joinPoint) {
-
handleLog(joinPoint, null);
-
}
-
-
/**
-
* 方法执行中出现了异常 会出现在@AfterThrowing中
-
*/
-
@AfterThrowing(value = "controllerAspect()", throwing = "e")
-
public void doAfter(JoinPoint joinPoint, Exception e) {
-
handleLog(joinPoint, e);
-
}
-
-
private void handleLog(JoinPoint joinPoint,Exception e) {
-
try {
-
//从joinPoint获得LogAnnotation注解
-
LogAnnotation controllerLog = giveController(joinPoint);
-
if(controllerLog == null)
-
{
-
return;
-
}
-
//获取request
-
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
-
//通过request获取session 然后获取用户信息
-
//通过request获取ip
-
-
//处理设置注解上的参数 也就是方法的描述
-
String desc = controllerLog.desc();
-
System.out.println(desc);
-
//保存数据库
-
-
} catch (Exception exp) {
-
//记录本地异常日志
-
logger.error("==前置通知异常==");
-
logger.error("异常信息:{}", exp.getMessage());
-
exp.printStackTrace();
-
}
-
}
-
-
/**
-
* 是否存在注解,如果存在就记录日志
-
* @param joinPoint
-
* @param controllerLog
-
* @return
-
* @throws Exception
-
*/
-
private static LogAnnotation giveController(JoinPoint joinPoint) throws Exception
-
{
-
/*
-
* JoinPoint可以获取什么:
-
l java.lang.Object[] getArgs():获取连接点方法运行时的入参列表;
-
l Signature getSignature() :获取连接点的方法签名对象;
-
l java.lang.Object getTarget() :获取连接点所在的目标对象;
-
l java.lang.Object getThis() :获取代理对象本身;
-
*/
-
Signature signature = joinPoint.getSignature();
-
/*
-
* MethodSignature可以获取什么:
-
Class getReturnType(); 获取方法的返回类型
-
Method getMethod(); 获取方法本身
-
*/
-
MethodSignature methodSignature = (MethodSignature) signature;
-
/**
-
* Method可以获取方法上的各种信息 比如方法名称 方法参数 注解 参数上的注解等。
-
*/
-
Method method = methodSignature.getMethod();
-
-
if(method != null)
-
{
-
return method.getAnnotation(LogAnnotation.class);
-
}
-
return null;
-
}
-
}
声明:aop:aspectj-autoproxy
关于aop:aspectj-autoproxy:
通过aop命名空间的<aop:aspectj-autoproxy />声明自动为spring容器中那些配置@aspectJ切面的bean创建代理,织入切面。当然,spring 在内部依旧采用AnnotationAwareAspectJAutoProxyCreator进行自动代理的创建工作,但具体实现的细节已经被<aop:aspectj-autoproxy />隐藏起来了
<aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,当配为<aop:aspectj-autoproxy poxy-target-class="true"/>时,表示使用CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。
-
<aop:aspectj-autoproxy />
在Controller方法中加入注解:
-
@RequestMapping(value="/test1")
-
@LogAnnotation(desc="test1方法")
-
public String test1(HttpServletRequest request)
-
{
-
request.setAttribute("att1", "val1");
-
return "test1";
-
}