使⽤⾃定义@Logger注解实现⽇志记录
前⾔:曾⼀直想拥有⾃⼰的的博客,将⾃⼰对java的感悟记录下来,由于时间原因⼀直没有⾏动,这是我的第⼀次随笔,好的话关注⼀下,谢谢。
创建@Logger注解的作⽤
1.封装⼀些常⽤的⽇志记录以及统计功能
2.可以⾃定义记录⽅法,解耦,脱离传统的业务⽅法⾥⾯记录⽇志
@Logger注解⾃定义之前我们需要⽤到以下技术:
1.java反射机制
2.动态代理
3.Spring AOP(实际aop的实现可以归结动态代理)
对以下技术做⼀个简单的概括:
**(1).java反射:
反射是运⾏中的程序检查⾃⼰和软件运⾏环境的能⼒,它可以根据它发现的进⾏改变。通俗的讲就是反射可以在运⾏时根据指定的类名获得类的信息。
(2)动态代理:动态代理的实现也是根据反射实现,可以说优秀的代码设计,都离不开反射。
(3)Spring Aop:spring框架提供的其中之⼀模块就是Aop,它是对OOP的⼀个补充,OOP是⾯向对象,它则是⾯向切⾯。
Aop的应⽤场景:
流量统计 ⽇志记录 程序监控 归结⼀点:⼀切和业务逻辑⽆关的,都可以⽤AOP来完成。**
说了这么多,接下来我们具体来使⽤⾃定义注解,将以上的类容全部运⽤⼀下:
(该注解⽬前只实现了⼀些最基本的记录,后⾯会继续完善)
⾸先定义⼀个@Logger注解:
package com.ph.licenceserver.Annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* ⽇志注解类,提供简单的⽇志操作功能
* @author LT
*
*/
@Target({PARAMETER,METHOD})
@Retention(RUNTIME)
@Documented
public @interface Logger {
String value() default"";//设置打印信息
String type() default Constant.INFO;//设置打印类型
boolean isPrintTimeStamp() default true;//是否答应timestamp类型的时间,主要⽤于性能测试
boolean EnableIpAddress() default true;//是否开启ip记录功能
boolean EnableURL() default true;//是否开启url记录功能
boolean EnableRequestParmas() default true;//请求参数记录
boolean EnableSigar() default false;//开启监控功能
}
创建⼀个注解的处理类(Handle):
package com.ph.licenceserver.AnnotationHandle;
import flect.InvocationTargetException;
import flect.Method;
SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.t.request.RequestContextHolder;
import org.t.request.ServletRequestAttributes;
import com.ph.licenceserver.Annotation.Logger;
/**
* 注解处理类
*
* @author LT
*
*/
public class LoggerHandles {
String value = "";
String type = "INFO";
boolean timestampe;
boolean address;
boolean url;
boolean sigar;
boolean requestParmas;
JoinPoint joinPoint;
org.apache.log4j.Logger logger;
public void setLoggerInfo(Class<?> clazz,JoinPoint joinPoint) {
this.joinPoint=joinPoint;
logger = org.apache.Logger(clazz);//获取⽇志对象
Method[] methods = Methods();获取所有切⼊点所在类的所有⽅法
for (Method method : methods) {//遍历切⼊⽅法所在类的所有成员⽅法,是否有Logger.class类型的注解并获取它的值 if (method.isAnnotationPresent(Logger.class)) {
value = Annotation(Logger.class).value();
type = Annotation(Logger.class).type();
timestampe = Annotation(Logger.class)
.isPrintTimeStamp();
address = Annotation(Logger.class).EnableIpAddress();
url = Annotation(Logger.class).EnableURL();
sigar = Annotation(Logger.class).EnableSigar();
requestParmas = Annotation(Logger.class)
.EnableRequestParmas();
}
}
}
public void LoggerHandle() {
if ("ERROR".equals(type)) {
<(value);
setLoggerMessage(type,joinPoint);
} else if ("INFO".equals(type))
logger.info(value);
setLoggerMessage(type,joinPoint);
}
public void setLoggerMessage(String value,JoinPoint joinPoint) {
System.out.println(value);
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
HttpServletRequest request = Request();
Method method;
/**
利⽤反射,实现⽅法的动态获取,如果这⾥不⽤method.invoke()⽅法,logger的info和error⽅法就要进⾏⼤量的判断 */
try {
method = Class().LowerCase(),Object.class);
method.invoke(this.logger, value);
if (timestampe) {
method.invoke(this.logger,"当前时间戳:" + System.currentTimeMillis());
}
if (address) {
method.invoke(this.logger,"IpAddress:" + RemoteAddr());
}
if (url) {
method.invoke(this.logger,"URL:" + RequestURL().toString());
}
if (requestParmas) {
method.invoke(this.logger,"HTTP_METHOD:"+Method());
method.invoke(this.logger,"CLASS_METHOD : "
+ Signature().getDeclaringTypeName() + "."
+ Signature().getName());
@SuppressWarnings("unchecked")
Enumeration<String> enu = ParameterNames();
String message = "";
while (enu.hasMoreElements()) {
String paraName = (String) Element();
message = (paraName + ": " + Parameter(paraName));
}
method.invoke(this.logger,message);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();//这⾥就直接打印,不进⾏处理了,明⽩就⾏
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
/*
* if(timestampe){ ("当前时间戳:"+System.currentTimeMillis()); }
* if(address){ ("IpAddress:"+RemoteAddr()); }
* if(url){ ("URL:"+RequestURL().toString()); }
* if(requestParmas){
*
* @SuppressWarnings("unchecked") Enumeration<String> enu =
* ParameterNames(); String message=""; while
* (enu.hasMoreElements()) { String paraName = (String)
* Element(); message=(paraName + ": " +
* Parameter(paraName)); } (message); }
*/spring aop应用场景
}
public String DateNow(){
return new SimpleDateFormat("yyyy-MM-dd").format(new Date());
}
}
创建spring Aop:
package com.ph.licenceserver.Aop;
import flect.Method;
import java.util.Arrays;
import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.t.request.RequestContextHolder;
import org.t.request.ServletRequestAttributes;
import com.ph.licenceserver.AnnotationHandle.LoggerHandles;
@Aspect
@Component
public class LoggingAspect {
private Logger logger = Class());
// 对以下ller.Controller类中的所有⽅法进⾏切⼊
public static Long starttime = null;
@Pointcut("execution(public * com.ph.licenceserver.web.*.*(..))")//利⽤表达式定义需要切⼊的点
private void method() {
}
@After("method()")
//在切⼊⽅法执⾏后执⾏该⽅法
public void recordLog(JoinPoint joinPoint) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
HttpServletRequest request = Request();
String targetName = Target().getClass().getName();//获取连接点躲在⽬标对象的类信息的类名 String methodName = Signature().getName();//获取连接点的⽅法签名对象的⽅法名
Class targetClass;
try {
targetClass = Class.forName(targetName);//获得类名对应的类
Object[] arguments = Args();//或得连接点⽅法传⼊的参数
Method[] methods = Methods();//得到⽅法名
for (Method method : methods) {
if (Name().equals(methodName)) {
Class[] clazzs = ParameterTypes();
if (clazzs.length == arguments.length) {
try {
LoggerHandles handle=wInstance();
handle.Target().getClass(),joinPoint);
handle.LoggerHandle();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
break;
}
}
}
} catch (ClassNotFoundException e) {
使⽤⾃定义注解运⽤在之前定义的controller类上(以下涉及到隐私内容所以我将⽅法体中的内容去掉了,不影响⽇志记录结果)
来查看⼀下crontroller接受请求之后有@Logger注解有没有输出相应类容(刷新之后):
⽇志后台统计信息:
以上就是使⽤创建注解的全过程,可能有⼈要问了,为什么要使⽤这个注解,直接利⽤spring AOP来定
义切⾯,在@Before注解的⽅法或@Around注解所在⽅法中直接实现⽇志记录不是也可以吗?
确实可以,但是使⽤注解的⽅式我们可以配置我们想配置的⽅法,只需要使⽤@Pointcut定义切⼊点,在切⼊点所在⽅法之内配置@Logger注解,该注解就会⽣效。利⽤xml配置的形式配置aop更⽅便,不⽤操作具体的类 } catch (ClassNotFoundException e) {
e .printStackTrace ();
}
}
@AfterReturning("method()")
public void doAfterReturning(JoinPoint joinPoint) {
Long time = System .currentTimeMillis () - starttime ;
logger .info ("⽤时:" + time .toString () + "毫秒");
}}
@RequestMapping ("/all.do")
@ResponseBody
@com .ph.licenceserver.Annotation.Logger(value="执⾏了logger 注解",type="INFO")
public PageUtil getCountAll (@RequestBody Query query,HttpServletRequest request){
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论