文章目录
最终效果写前面
环境准备(Maven写的)
导入log4j的依赖
<!--日志包-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
<version>2.6.2</version>
</dependency>
因为要输出日志,我用的log4j2日志配置。在resources下配置log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志文件 -->
<Configuration status="WARN">
<Appenders>
<!--Console向控制台追加日志 target的值SYSTEM_OUT表示向系统控制台输出 -->
<Console name="Console" target="SYSTEM_OUT">
<!-- 输出日志格式信息 -->
<PatternLayout pattern="日志log:%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n \n"/>
</Console>
</Appenders>
<!-- 记录哪些类的日志信息 -->
<Loggers>
<!--DEBUG 是日志级别 调试信息也会记录 name: 是要进行日志记录的目录 -->
<Logger name="com.xgf" level="DEBUG"/>
<Root level="error">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
这里面,你只需要配置Loggers
下的logger
标签的name属性就行,这个name的值就是你要进行日志管理的包的类路径,levelsl是你的管理级别,我设置是debug。按你个人需求配置
只需要修改这个name就行。
<Logger name="com.xgf" level="DEBUG"/>
编写自己的日志记录和方法增强处理
1. 创建自己的切面接口和实现类
切面接口IMyAspect
,实现增强方法
//切面类接口
public interface IMyAspect {
//方法调用前执行
public void init();
//方法调用后执行
public void destroy();
}
切面实现类MyAspectImpl
//切面类 增强方法
public class MyAspectImpl implements IMyAspect {
//方法执行前执行
public void init(){
System.out.println(" MyAspect - init方法,方法执行前调用 ");
}
//方法执行后执行
public void destroy(){
System.out.println(" MyAspect - destroy方法,方法执行后调用");
}
}
2. 创建我的代理类
Proxy类创建代理对象的newProxyInstance
方法介绍:
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
参数介绍:
- 参数1:ClassLoader loader 类加载器 , 用来加载代理对象
- 参数2:Class<?>[] interfaces 目标类的字节码对象数组. 因为代理的是接口,需要知道接口中所有的方法
- 参数3:InvocationHandler h 执行句柄, 代理对象处理的核心逻辑就在该接口中
通过泛型实现通用性。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//日志代理类,泛型传入被代理对象
public class MyLogProxy<T> implements InvocationHandler {
private T byProxy; //被代理类接口
private IMyAspect myAspect; //切面接口,增强方法
private MyLog myLog; //日志切面类 -- 定义公共方法
//构造方法,参数1:被代理类 参数2:切面增强方法
public MyLogProxy(T byProxy, IMyAspect myAspect) {
//创建代理类的时候初始化日志类,并将被代理类作为参数传入日志
this.myLog = new MyLog(byProxy.getClass());
this.byProxy = byProxy;
this.myAspect = myAspect;
}
//创建一个日志代理对象
public Object createLogProxy(){
//类加载器
ClassLoader classLoader = byProxy.getClass().getClassLoader();
// Class<?>[] interfaces 被代理对象的实现接口(通过接口来找到方法)
Class<?>[] interfaces = byProxy.getClass().getInterfaces();
T logProxy = (T) Proxy.newProxyInstance(classLoader,interfaces,this);
System.out.println("创建"+byProxy+"的日志代理对象createLogProxy");
return logProxy;
}
//调用被代理类的方法,实现方法增强
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法执行前,调用切面增强
myAspect.init();
//获取方法执行的开始时间
long startTime = System.currentTimeMillis();
//调用被代理对象的方法,通过反射实现,满足通用性
Object invokeValue = method.invoke(byProxy, args);
//获取方法调用结束时间
long endTime = System.currentTimeMillis();
//方法执行后,调用切面增强
myAspect.destroy();
//调用自己的日志记录 method就是调用的被代理对象的方法
myLog.logInfo(method,args,invokeValue,startTime,endTime);
return invokeValue;
}
}
3. 创建自己的日志类
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.lang.reflect.Method;
import java.util.Arrays;
//日志类 增强方法 传入被代理类的,泛型实现通用
public class MyLog<T> {
//private static Logger log = LogManager.getLogger(byProxyClass.getName());
private Logger log;
private Class<T> byProxyClass;//被代理类
public MyLog(Class<T> byProxyClass){
this.byProxyClass = byProxyClass;
log = LogManager.getLogger(byProxyClass.getName());
}
//log4j2日志操作 输出日志信息
//参数 method当前方法,Object[] args 方法调用参数,invokeValue 方法运行的返回值,startTime 方法运行开始时间,endTime 方法运行结束时间
public void logInfo(Method method, Object[] args, Object invokeValue, Long startTime, Long endTime){
//debug形式输出
log.debug("[ MyLog记录:方法名:"+method.getName() + " 参数:"+ Arrays.toString(args)+" 返回值:"+invokeValue+" 执行耗时:"+(endTime-startTime)+"毫秒");
}
}
被代理类接口IUserDao
public interface IUserDao {
public void addUser(User user);
public void updateUser(User user);
public int deleteUser(User user);
}
被代理类的实现类UserDaoImpl
我这里没有实现对user的操作,只是打印输出
public class UserDaoImpl implements IUserDao {
public void addUser(User user) {
System.out.println("=== 增加addUser成功" + user + " ===");
}
public void updateUser(User user) {
System.out.println("=== 更新updateUser成功" + user + " ===");
}
public int deleteUser(User user) {
System.out.println("=== 删除deleteUser成功" + user + " ===");
return 1;
}
}
5. 创建测试类
public class TestJdbcLog {
@Test
public void test01(){
//创建user对象(参数),没有实际操作,仅仅做打印
User user = new User("username123","password456");
//创建被代理类
IUserDao iUserDao = new UserDaoImpl();
//创建切面类
IMyAspect myAspect = new MyAspectImpl();
//创建代理类 参数:1、被代理类 2、切面增强
MyLogProxy myProxy = new MyLogProxy(iUserDao,myAspect);
//通过代理类来创建实例 - 代理对象
IUserDao byProxy = (IUserDao)myProxy.createLogProxy();
//通过创建的被代理类的实例来进行方法操作
byProxy.addUser(user);
byProxy.deleteUser(user);
}
}
6. 这样就完成了一个对方法的日志记录和方法增强了。
输出结果:
创建com.xgf.dao.impl.UserDaoImpl@3aeaafa6的日志代理对象createLogProxy
MyAspect - init方法,方法执行前调用
=== 增加addUser成功User{username=‘username123’, password=‘password456’} ===
MyAspect - destroy方法,方法执行后调用
日志log:21:01:48.372 [main] DEBUG com.xgf.dao.IUserDao - [ MyLog记录:方法名:addUser 参数:[User{username=‘username123’, password=‘password456’}] 返回值:null 执行耗时:1毫秒
MyAspect - init方法,方法执行前调用
=== 删除deleteUser成功User{username=‘username123’, password=‘password456’} ===
MyAspect - destroy方法,方法执行后调用
日志log:21:01:48.376 [main] DEBUG com.xgf.dao.IUserDao - [ MyLog记录:方法名:deleteUser 参数:[User{username=‘username123’, password=‘password456’}] 返回值:1 执行耗时:1毫秒