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 @AutoLog
implemented 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?
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 @Pointcut
is 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 @Value
get 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 @EnableAutoLog
automatic 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 @AutoLog
specified method or class.
auto.log.pointcut
Of 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
We autoLogConfig.properties
customize 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.