在Spring Boot项目中,@SpringBootTest
和 @RunWith(SpringRunner.class)
是用于测试类的注解,它们一起开启了基于Spring应用上下文的集成测试。@Autowired
注解用于自动装配依赖到 IService
上,这是通过Spring AOP(面向切面编程)实现的。
在testAop()
方法中,当我们调用 service.getClass()
时,实际返回的是Service接口的一个代理类 (Service1$$EnhancerBySpringCGLIB$$f107fe5e
)。这通常是Spring AOP创建的,它包含了Service1的实际逻辑并可能添加了一些额外的功能,如切面通知(如事务管理、日志记录等)。
关于spring-boot-starter-aop
的配置,有两个关键点:
- 默认情况下,Spring Boot会启用AspectJ自动代理 (
proxyTargetClass=false
),这意味着它会在运行时动态创建代理类。如果你希望使用CGLIB(Code Generation Library)代替(即生成字节码),可以设置spring.aop.proxy-target-class
属性为true
。例如,在你的@Configuration
类中,你可以这样声明:
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AopConfig {
// ...
}
- 如果
proxy-target-class
属性未显式设置,Spring Boot会查找该属性是否存在,如果存在且值为true
,则按照指定方式启用代理。@ConditionalOnProperty
则允许你基于特定的配置条件来决定某个配置的生效与否。
要了解更多关于Spring Boot AOP的细节,可以查阅Spring-Boot-Starter-AOP
的官方文档或者深入分析@EnableAspectJAutoProxy
和@Aspect
注解的工作原理。
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
package com.programb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
package com.programb.aop;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Order(1)
public class AfterStartRunner implements CommandLineRunner {
private Logger logger = LoggerFactory.getLogger(this.getClass());
public void run(String... args) {
logger.debug("after start debug...");
logger.info("after start info...");
}
}
package com.programb.aop.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
/**
* 日志切面
*/
@Aspect
@Component
public class LogAspect {
@Pointcut("execution(public * com.xncoding.aop.controller.*.*(..))")
public void webLog(){
}
@Before("webLog()")
public void deBefore(JoinPoint joinPoint) throws Throwable {
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 记录下请求内容
System.out.println("URL : " + request.getRequestURL().toString());
System.out.println("HTTP_METHOD : " + request.getMethod());
System.out.println("IP : " + request.getRemoteAddr());
System.out.println("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());