您的位置:首页 > 编程语言 > Java开发

SpringBoot 使用AOP功能

2018-07-11 14:26 441 查看
    RPC,AOP都会用到代理,代理的技术有jdk的Proxy代理(必须实现接口),cglib(可以不实现接口,直接实现类),Javassist(jboss )而Spring boot本身也在方方面面使用了代理技术,在Spring中有两种动态代理方式,分别为jdk动态代理和CGLIB动态代理。
    两者主要区别:
1:jdk代理的目标对象必须实现若干接口,因为有接口,所以使系统更加松耦合。
而CGLIB代理就跟jdk代理刚刚相反目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类,代理类与目标类是继承关系,所以耦合性没有使用JDK的动态代理好。
2.:JDK动态代理(使用Java反射机制生成代理对象)Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),this),CGLIB动态代理使用Enhancer基于继承的方式,
底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。

下面主要讲述,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起效果了。

结论:就是不太清楚情况一,为什么不会报错,知道的牛人,可以留言喔!

稿毕!!!!!!

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: