How to dynamically modify spring aop aspect information? Make the automatic log output framework better

business background

A long time ago, an auto-log automatic log printing framework was open sourced .

Among them, for the spring project, the log output based on the aop aspect is implemented by default.

However, a problem was found. If the definition of the aspect is too large, the v0.2 version is @AutoLogimplemented based on annotations.

Only classes or methods with specified annotations will take effect, but this is very inconvenient to use.

How can we dynamically specify pointcut so that users can customize the range of cut planes when using it?

insert image description here

Principle of custom annotation aspect

conventional aop mode

@Aspect
@Component
@EnableAspectJAutoProxy
@Deprecated
public class AutoLogAop {

    @Pointcut("@within(com.github.houbb.auto.log.annotation.AutoLog)" +
            "|| @annotation(com.github.houbb.auto.log.annotation.AutoLog)")
    public void autoLogPointcut() {
    }

    /**
     * 执行核心方法
     *
     * 相当于 MethodInterceptor
     *
     * @param point 切点
     * @return 结果
     * @throws Throwable 异常信息
     * @since 0.0.3
     */
    @Around("autoLogPointcut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        // 日志增强逻辑
    }

}

It is found that the annotation attribute here @Pointcutis a constant and cannot be dynamically modified conveniently.

So I checked the information and found another more flexible way.

The way to specify pointcut

We @Valueget the aspect value of the property configuration by and give the default value. In this way, users can easily customize it.

/**
 * 动态配置的切面
 * 自动日志输出 aop
 * @author binbin.hou
 * @since 0.3.0
 */
@Configuration
@Aspect
//@EnableAspectJAutoProxy
public class AutoLogDynamicPointcut {

    /**
     * 切面设置,直接和 spring 的配置对应 ${},可以从 properties 或者配置中心读取。更加灵活
     */
    @Value("${auto.log.pointcut:@within(com.github.houbb.auto.log.annotation.AutoLog)||@annotation(com.github.houbb.auto.log.annotation.AutoLog)}")
    private String pointcut;

    @Bean("autoLogPointcutAdvisor")
    public AspectJExpressionPointcutAdvisor autoLogPointcutAdvisor() {
        AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
        advisor.setExpression(pointcut);
        advisor.setAdvice(new AutoLogAdvice());
        return advisor;
    }

}

Of course, the Advice here is different from the previous aop and needs to be re-implemented.

AutoLogAdvice

Just implement the MethodInterceptor interface.

/**
 * 切面拦截器
 *
 * @author binbin.hou
 * @since 0.3.0
 */
public class AutoLogAdvice implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        // 增强逻辑
    }

}

After introducing the principle, let's take a look at the effect of the improved log printing component.

spring integrated use

For a complete example, refer to SpringServiceTest

maven import

<dependency>
    <groupId>com.github.houbb</groupId>
    <artifactId>auto-log-spring</artifactId>
    <version>0.3.0</version>
</dependency>

Annotation statement

Enable @EnableAutoLogautomatic logging output with

@Configurable
@ComponentScan(basePackages = "com.github.houbb.auto.log.test.service")
@EnableAutoLog
public class SpringConfig {
}

test code

@ContextConfiguration(classes = SpringConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringServiceTest {

    @Autowired
    private UserService userService;

    @Test
    public void queryLogTest() {
        userService.queryLog("1");
    }

}
  • output result
信息: public java.lang.String com.github.houbb.auto.log.test.service.impl.UserServiceImpl.queryLog(java.lang.String) param is [1]
五月 30, 2020 12:17:51 下午 com.github.houbb.auto.log.core.support.interceptor.AutoLogMethodInterceptor info
信息: public java.lang.String com.github.houbb.auto.log.test.service.impl.UserServiceImpl.queryLog(java.lang.String) result is result-1
五月 30, 2020 12:17:51 下午 org.springframework.context.support.GenericApplicationContext doClose

Section customization

Principle explanation

The aspect of spring aop is read from @Value("${auto.log.pointcut}"), the default is the value@within(com.github.houbb.auto.log.annotation.AutoLog)||@annotation(com.github.houbb.auto.log.annotation.AutoLog)

That is, the default is to read the @AutoLogspecified method or class.

auto.log.pointcutOf course, this is not convenient enough. We hope that we can specify the scanning range of spring aop just like we usually write aop annotations, and just specify the property value of in spring directly .

test example

complete test code

We autoLogConfig.propertiescustomize the scope of package scanning in the configuration file:

auto.log.pointcut=execution(* com.github.houbb.auto.log.test.dynamic.service.MyAddressService.*(..))

custom test service

package com.github.houbb.auto.log.test.dynamic.service;

import org.springframework.stereotype.Service;

@Service
public class MyAddressService {

    public String queryAddress(String id) {
        return "address-" + id;
    }

}

Customize the spring configuration, specify the configuration file we defined. Springboot or something can be specified directly in application.properties, here is only for demonstration.

@Configurable
@ComponentScan(basePackages = "com.github.houbb.auto.log.test.dynamic.service")
@EnableAutoLog
@PropertySource("classpath:autoLogConfig.properties")
public class SpringDynamicConfig {
}

test

@ContextConfiguration(classes = SpringDynamicConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringDynamicServiceTest {

    @Autowired
    private MyAddressService myAddressService;

    @Autowired
    private MyUserService myUserService;

    @Test
    public void queryUserTest() {
        // 不会被日志拦截
        myUserService.queryUser("1");
    }

    @Test
    public void queryAddressTest() {
        // 会被日志拦截
        myAddressService.queryAddress("1");
    }

}

open source address

In order to facilitate everyone to learn, the project has been open source.

Github: github.com/houbb/auto-…

Gitee: gitee.com/houbinbin/a…

summary

This project has been stuck in the way of annotation for a long time, and it is not very convenient for me to use it personally.

Only recently did I think of a way to improve, and people still have to keep learning and improving.

Regarding the log, I recently learned about aspect's compile-time enhancement and agent-based runtime enhancement. These two methods are very interesting, and I will make learning records when I have the opportunity.

Guess you like

Origin juejin.im/post/7258483153869865020