实现自己的日志记录,通过JDBC动态代理写一个自己的日志记录,和方法增强(AOP)

最终效果写前面

在这里插入图片描述

环境准备(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 执行句柄, 代理对象处理的核心逻辑就在该接口中

通过泛型实现通用性。

扫描二维码关注公众号,回复: 11875901 查看本文章
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毫秒

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_40542534/article/details/108986006
今日推荐