当前位置: 首页 > news >正文

织梦培训机构网站模板centos7部署wordpress

织梦培训机构网站模板,centos7部署wordpress,展厅设计理念和设计构思,新莱芜客户端目录 一、为什么需要代理? 二、代理长什么样? 三、Java通过什么来保证代理的样子? 四、动态代理实现案例 五、动态代理在SpringBoot中的应用 导入依赖 数据库表设计 OperateLogEntity实体类 OperateLog枚举 RecordLog注解 上下文相…

目录

一、为什么需要代理?

二、代理长什么样?

三、Java通过什么来保证代理的样子?

四、动态代理实现案例

五、动态代理在SpringBoot中的应用

导入依赖

数据库表设计

OperateLogEntity实体类

OperateLog枚举

RecordLog注解

上下文相关类

OperateLogAspect切面类

OperateLogMapper


一、为什么需要代理?

代理可以无侵入式地给对象增强其他的功能

例如以下方法

public static void playGame() {System.out.println("玩游戏");
}

现在要对这个方法进行增强,在玩游戏之前要先吃饭,玩完游戏后要睡觉。

下面这种修改方法就是侵入式修改,对原始的方法进行修改。缺点是会使代码变得繁琐,扩展性变差。原本playGame()方法就是用来玩游戏的,吃饭和睡觉不属于玩游戏的范畴。

public static void playGame() {System.out.println("吃饭");System.out.println("玩游戏");System.out.println("睡觉");
}

为什么需要代理?

代理就是调用playGame()方法,并且在调用之前先吃饭,玩完游戏后再睡觉。

类似于下面这种修改方式

public class Test {public static void main(String[] args) {action();}public static void action() {System.out.println("吃饭");playGame();System.out.println("睡觉");}public static void playGame() {System.out.println("玩游戏");}
}

我们并没有直接调用playGame()方法,而是通过action()方法间接调用playGame()方法。

所以代理的目的就是在调用方法时,能在调用前或者调用后做一些事,从而达到在不修改原始方法的基础上,对原始方法进行增强。

当然我们要实现代理并不是用以上的方法,上面的案例只是解释代理的作用是什么。

二、代理长什么样?

代理里面就是对象要被代理的方法

简单理解,代理就是一个对象,这个对象里面有要被代理的方法。

被代理对象里面有playGame()方法,代理对象里面也有playGame()方法,并且是增强后的playGame()方法。

也就是说我们直接从代理对象里调用方法就行了,代理就是一个对象。

那么如何获取代理对象呢?

代理对象应该长得和被代理对象差不多才行,所以我们可以根据被代理对象来创建代理对象。

三、Java通过什么来保证代理的样子?

上面说到要根据被代理对象来创建代理对象,既然两者是相似的,可以想到如果代理对象和被代理对象继承了同一个父类,两者不就相似了吗?

因为代理对象和被代理对象虽然都有playGame()方法,但是方法的实现不同,只是方法的名称是一样的。

那么代理对象和被代理对象应该实现同一个接口,接口中的方法也就是要被代理的方法。

四、动态代理实现案例

我们先定义一个OnePerson类,其中playGame()方法就是要代理的方法,所以我们再定义一个Person接口。Person接口里面写playGame()抽象方法,代理对象也要实现Person接口并且重写playGame()方法。

public class OnePerson implements Person {private String name;private String gender;private Integer age;@Overridepublic void playGame() {System.out.println(this.name + "正在玩游戏");}public OnePerson() {}public OnePerson(String name, String gender, Integer age) {this.name = name;this.gender = gender;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "OnePerson{" +"name='" + name + '\'' +", gender='" + gender + '\'' +", age=" + age +'}';}
}
public interface Person {void playGame();
}

ProxyUtils

定义生成代理对象的工具类

这里用到反射,Method调用的方法就是原始的方法。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class ProxyUtils {public static Person createProxy(OnePerson onePerson) {return (Person) Proxy.newProxyInstance(ProxyUtils.class.getClassLoader(),  // 类加载器new Class[]{Person.class},          // 接口,指定要代理的方法new InvocationHandler() {           // 调用并增强原始方法@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String name = onePerson.getName();if (method.getName().equals("playGame")) {System.out.println(name + "在吃饭");}Object object = method.invoke(onePerson, args);if (method.getName().equals("playGame")) {System.out.println(name + "在睡觉");}return object;}});}
}

案例测试

public class Test {public static void main(String[] args) {OnePerson onePerson = new OnePerson("艾伦", "男", 15);Person person = ProxyUtils.createProxy(onePerson);person.playGame();}
}

测试结果

可以看到我们并没有在OnePerson类中修改playGame()方法,但是成功地对playGame()方法进行了增强。

五、动态代理在SpringBoot中的应用

动态代理在SpringBoot中就是面向切面编程(AOP),可以用来记录操作日志、公共字段自动填充等实现。

下面介绍如何实现记录操作日志

导入依赖

<!--AOP起步依赖-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--fastjson-->
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.83</version>
</dependency>

数据库表设计

create table if not exists tb_operate_log
(id              bigint auto_increment comment '主键id'primary key,class_name      varchar(128)  not null comment '类名',method_name     varchar(128)  not null comment '方法名',method_param    varchar(1024) not null comment '方法参数',method_return   varchar(2048) not null comment '方法返回值',cost_time       bigint        not null comment '方法运行耗时;单位:ms',create_username varchar(16)   not null comment '方法调用者用户名',create_time     datetime      not null comment '创建时间',update_time     datetime      not null comment '更新时间',constraint idunique (id)
)comment '操作日志表';

OperateLogEntity实体类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.time.LocalDateTime;/*** @Description: 操作日志表实体类* @Author: 翰戈.summer* @Date: 2023/11/21* @Param:* @Return:*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OperateLogEntity {private Long id;private String className;private String methodName;private String methodParam;private String methodReturn;private Long costTime;private String createUsername;private LocalDateTime createTime;private LocalDateTime updateTime;
}

OperateLog枚举

/*** @Description: 日志操作类型* @Author: 翰戈.summer* @Date: 2023/11/21* @Param:* @Return:*/
public enum OperateLog {//记录操作RECORD}

RecordLog注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @Description: 注解,用于标识需要进行记录操作日志的方法* @Author: 翰戈.summer* @Date: 2023/11/21* @Param:* @Return:*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RecordLog {//日志操作类型,RECORD记录操作OperateLog value();}

上下文相关类

ThreadLocal线程局部变量,将信息放入上下文,后面要用可以直接取出。

public class BaseContext {public static ThreadLocal<String> threadLocal = new ThreadLocal<>();public static void setContext(String context) {threadLocal.set(context);}public static String getContext() {return threadLocal.get();}public static void removeContext() {threadLocal.remove();}
}

OperateLogAspect切面类

import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;import java.time.LocalDateTime;
import java.util.Arrays;/*** @Description: 切面类,实现记录操作日志* @Author: 翰戈.summer* @Date: 2023/11/21* @Param:* @Return:*/
@Aspect
@Component
@RequiredArgsConstructor
public class OperateLogAspect {private final OperateLogMapper operateLogMapper;/*** @Description: 切入点* @Author: 翰戈.summer* @Date: 2023/11/21* @Param:* @Return: void*/@Pointcut("execution(* com.demo.controller.*.*(..)) && @annotation(com.demo.annotation.RecordLog)")public void recordLogPointcut() {}/*** @Description: 环绕通知,进行记录操作日志* @Author: 翰戈.summer* @Date: 2023/11/21* @Param: ProceedingJoinPoint* @Return: Object*/@Around("recordLogPointcut()")public Object recordLog(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {//获取类名String className = proceedingJoinPoint.getTarget().getClass().getName();//获取方法名String methodName = proceedingJoinPoint.getSignature().getName();//获取方法参数Object[] args = proceedingJoinPoint.getArgs();String methodParam = Arrays.toString(args);Long begin = System.currentTimeMillis();// 方法运行开始时间Object result = proceedingJoinPoint.proceed();// 运行方法Long end = System.currentTimeMillis();// 方法运行结束时间//方法耗时Long costTime = end - begin;//获取方法返回值String methodReturn = JSONObject.toJSONString(result);String username = BaseContext.getContext();// 当前用户名LocalDateTime now = LocalDateTime.now();// 当前时间OperateLogEntity operateLog = new OperateLogEntity(null, className, methodName,methodParam, methodReturn, costTime, username, now, now);operateLogMapper.insertOperateLog(operateLog);return result;}
}

OperateLogMapper

import org.apache.ibatis.annotations.Mapper;/*** @Description: 操作日志相关的数据库操作* @Author: 翰戈.summer* @Date: 2023/11/21* @Param:* @Return:*/
@Mapper
public interface OperateLogMapper {void insertOperateLog(OperateLogEntity operateLog);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.demo.mapper.OperateLogMapper"><!--记录操作日志--><insert id="insertOperateLog">insert into tb_operate_log (id, class_name, method_name, method_param,method_return, cost_time, create_username, create_time, update_time)values (null, #{className}, #{methodName}, #{methodParam},#{methodReturn}, #{costTime}, #{createUsername}, #{createTime}, #{updateTime});</insert>
</mapper>

通过给controller层的接口方法加上@RecordLog(OperateLog.RECORD)注解即可实现记录操作日志,方便以后的问题排查。

《AOP如何实现公共字段自动填充》

https://blog.csdn.net/qq_74312711/article/details/134702905?spm=1001.2014.3001.5502 

http://www.yayakq.cn/news/810001/

相关文章:

  • 网站开发找哪家中国广告公司100强
  • 长沙医院网站建设外贸网有哪些
  • 广州h5网站制作做网站时怎样申请域名
  • html5网站优点北京建设信息网
  • 百度怎样做网站苏州网站建设电话
  • 最流行的网站开发语言怎么用阿里云服务器做网站
  • 大兴网站建设网站图片不轮播
  • 列举网站建设的基本流程网站系统繁忙是什么意思
  • 广州seo网站推广优化网站开发core文件作用
  • 山石网站超市wordpress 不用插件代码高亮
  • 零成本搭建自己的网站30个无加盟费的项目
  • 网站侧面的虚浮代码哪些论坛是wordpress
  • 国外网站注册软件建设银行信用卡管理中心网站
  • 建设网站地图素材网站建设优化一体
  • 给公司做网站这个工作怎么样电影网站怎么做
  • 做网站的素材和步骤百度地图手机网站开发
  • 个人使用网站建筑兼职招聘网
  • 如何做好营销型网站用户体验卖货到海外的免费平台
  • 足球网站模板wordpress本地ftp
  • 外贸网站如何做推广网站建设策划图片
  • 网站建 设方案说明书温州哪里可以做企业网站
  • 网站建设与管理基础及实训(php版)成都网站建设四川冠辰网站建设
  • 杭州网站设计网页长沙建设工程官方网站
  • wordpress多站点多域名插件佛山市南海区交通建设网站
  • 乐云seo网站建设性价比高无锡网页建站公司
  • 网站优化的推广能制作网页的软件是
  • 地方门户网站盈利股权融资
  • 汕头网站制作找哪里网站域名被重定向
  • 武隆网站建设报价厂房设计
  • 网站建设招标采购需求章丘网站开发培训