Web 细节汇总(2)

1. AOP 的实现方式

AOP:面向切面编程,采用横向抽取的机制取代了传统的纵向继承体系

1.1 动态代理

Spring 中的 aop 通常是在运行时内存中临时生成代理类,故而又称作运行时增强。运行时增强其实就是动态代理,其底层实现有两种:

  1. 需增强的目标类有接口,采用 JDK 中的动态代理
    这种实现要求目标类必须有接口,因为 JDK 动态代理生成的代理类已经继承Proxy类,Java 的单继承特性决定了该方式只能通过接口来实现增强
  2. 目标类没有接口,采用 CGLIB 动态代理
    CGLIB 的原理是通过字节码处理框架ASM来转换字节码并生成目标类的子类,调用子类方法从而达到增强目的。该方式的缺陷在于,被代理类及被代理方法如果被 final 修饰则无法完成增强逻辑

在 JDK6、JDK7、JDK8 逐步对JDK动态代理优化后,在调用次数较少的情况下,JDK代理效率高于CGLIB代理效率。只有当进行大量调用的时候,JDK6 和 JDK7 比CGLIB代理效率低一点,但到 JDK8 时JDK代理效率高于CGLIB代理

1.2 静态代理

在 Java 类加载期通过字节码转换,将增强逻辑织入切入点(目标类)完成增强的方式就是LTW(Load Time Weaving),即静态代理,也被称作编译时增强

这种方式主要依赖于Java探针技术,其核心为 java.lang.instrument 包。这个包在 JDK5.0 时引入,借助该包编写增强逻辑代码打成 jar 包,之后通过 -javaagent 参数来指定Java代理包即可启用,参数格式如下。代理包个数是不限的,指定多个则会按指定的先后执行,执行完各个 agent 后才会执行被代理类方法

-javaagent:<jarpath>[=options]

java.lang.instrument 包在 JVM 启动时会装配并应用 ClassTransformer,对类字节码进行转换,进而实现AOP的功能

  • Java 探针技术已经在开源框架 spring-loaded 中应用,可以使用该框架实现 jar 包热部署

Refer:Java探针-Java Agent技术


2. @Value 注入 Map 类型数据

SpringBoot 提供的 @Value 注解可以很方便的完成常规属性的注入,但是在注入Map类型的数据需要一些特别的处理。通常 Map 与 List 类型的属性在 application.yml文件中配置如下

  • yml 配置
    需注意配置为 Map 的 value 要使用双引号包裹,否则无法正确解析

    nathan:
     topics: topic1,topic2,topic3
     maps: "{key1: 'value1', key2: 'value2'}"
    
  • Java 引用
    注入 Map 时使用了 #{}包裹目标key,其实是表示使用 EL 表达式

      @Value("#{${nathan.maps}}")
      private Map<String, String> fundMatchFactor;
    
      @Value("${nathan.topics}")
      private List<String> topics;
    

3. Slf4j 日志框架打印堆栈

SpringBoot 项目集成 Slf4j日志框架打印 log 的时候,调用其 log.error() 方法 传入一个参数只会打印出很简略的错误描述,缺少足够的信息定位问题。查看源码发现其提供了多个方法重载,其中有如下方法声明

void error(String var1);

void error(String var1, Object var2);

void error(String var1, Object var2, Object var3);

void error(String var1, Object... var2);

void error(String var1, Throwable var2);

当使用两个参数的方法 error(String message, Throwable t),且第二个参数为 Throwable 类型时,才会将完整的异常堆栈打印出来,正确使用示例如下

@Slf4j
public class ExceptionTest {
    @Test
    public void test() {
        log.error("ExceptionDetail|",  new InternalException(ErrorFundRouteEnum.RC_ERROR_INNER_ERROR));
    }
}

4. Protobuf 的使用注意

在Java 中使用 Protobuf 时需要注意,当通过 build() 方法生成一个pb对象后,要再修改其中的内容需要调用 toBulider()使其回到可编辑的状态,最后再调用build() 方法保存修改,否则修改不会写入到 pd 对象中。另外每调用一次build() 方法都会生成一个新的 pb 对象,这点尤其需要注意

 RequestBasic requestBasic = RequestBasic.newBuilder().setClientInfo("hhh").build();
 // 未调用 build() 方法保存修改,内容不会改变
 requestBasic.toBuilder().setClientInfo("ggg");
 System.out.println(requestBasic.toString());
发布了97 篇原创文章 · 获赞 88 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_45505313/article/details/103463974
今日推荐