RPC,AOP都会用到代理,代理的技术有jdk的Proxy代理(必须实现接口),cglib(可以不实现接口,直接实现类),Javassist(jboss )而Spring boot本身也在方方面面使用了代理技术,在Spring中有两种动态代理方式,分别为jdk动态代理和CGLIB动态代理。
下面主要讲述,springboot如何使用AOP功能
1.POM文件中添加依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.在application.properties中加入配置
spring.aop.auto=true
PS:其实springboot此配置是默认开启的,所以根本可以不用管了,在Springboot中使用过注解配置方式的人会问是否需要在程序主类中增加@EnableAspectJAutoProxy
来启用,实际并不需要。看下面关于AOP的默认配置属性,其中spring.aop.auto
属性默认是开启的,也就是说只要引入了AOP依赖后,其实默认已经增加了@EnableAspectJAutoProxy
。
# AOP
spring.aop.auto=true # Add @EnableAspectJAutoProxy.
spring.aop.proxy-target-class=false # Whether subclass-based (CGLIB) proxies are to be created (true)
此处是设置是否开启CGLIB代理,默认不开启,相当于spring xml中
<aop:aspectj-autoproxy proxy-target-class="true"/>,
不过后面会有点奇怪的问题,springboot中,不管这个项是否设置为true或者false,都不会跟以前spring项目中,
如果没有设置为true,当代理类没有继承接口,启动项目的时候会报错。而springboot项目中,会自动转换成使用
CGLIB进行动态代理,其中原理是怎么实现,就没有去看底层代码了,估计底层进行了改造吧!
3.利用注解方式,实现AOP实现类。
import java.util.Arrays;import javax.servlet.http.HttpServletRequest;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;@Aspect
@Component
public class WebLogAspect {private Logger logger = LoggerFactory.getLogger(WebLogAspect.class);@Pointcut("execution(public * com.springboot.test.controller.*.*(..))")public void webLog(){System.out.println("begin");}@Before("webLog()")public void doBefore(JoinPoint joinPoint) throws Throwable {// 接收到请求,记录请求内容ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();// 记录下请求内容logger.info("URL : " + request.getRequestURL().toString());logger.info("HTTP_METHOD : " + request.getMethod());logger.info("IP : " + request.getRemoteAddr());logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));}@AfterReturning(returning = "ret", pointcut = "webLog()")public void doAfterReturning(Object ret) throws Throwable {// 处理完请求,返回内容logger.info("RESPONSE : " + ret);}}
测试:
情况1:spring.aop.proxy-target-class=false,实现类没有继承接口。
上图可以说明使用了CGLIB动态代理。这里就可以看出,spring.aop.proxy-target-class好像并没有其效果,这个我都没有去深究了。有谁知道的,请留言一下咯!
情况2:spring.aop.proxy-target-class=false,实现类继承了接口。
上图可以看出使用了jdk动态代理!
情况3:spring.aop.proxy-target-class=true,实现类继承了接口。
上图可以看出使用了CGLIB动态代理。这里就可以看出,spring.aop.proxy-target-class起效果了。
结论:就是不太清楚情况一,为什么不会报错,知道的牛人,可以留言喔!