表格引用 https://blog.csdn.net/erica_1230/article/details/51441419
序号 | 动态代理策略 | 不能被事务增强的方法 |
---|---|---|
1 | 基于接口的动态代理 | 除public外的其他所有的方法,此外public static也不能被增强 |
2 | 基于CGLib的动态代理 | private、static、final的方法 |
###service代码 |
package com.xyy.springboot.services;
import com.xyy.springboot.domain.BaseUser;
public interface BaseService {
/**
* 切面日志
*/
void aspectLog();
void aspectLogArgs(BaseUser baseUser, int i);
}
###实现类代码
该类使用@BaseTypeLog作为切点
package com.xyy.springboot.servicesImpl;
import com.xyy.springboot.configuration.BaseMethodLog;
import com.xyy.springboot.configuration.BaseTypeLog;
import com.xyy.springboot.domain.BaseUser;
import com.xyy.springboot.repository.BaseUserRepository;
import com.xyy.springboot.services.BaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
@Service("baseService")
//自己写的日志注解,整个类的方法都应用
@BaseTypeLog
public class BaseServiceImpl implements BaseService{
@Autowired
private BaseUserRepository baseUserRepository;
@Autowired
private BaseService baseService;
@Autowired
private ApplicationContext applicationContext;
@Override
@BaseMethodLog
public void aspectLog() {
int i = 0;
BaseUser baseUser = new BaseUser();
baseUser.setAge(18);
baseUser.setName("xyy");
//如果类实现了接口会使用jdk的代理方式,否则使用cglib的方式
//事物的实现原理同aop一样
//spring的动态代理机制,在执行目标方法的时候,先获取目标方法的代理类,在将目标方法和增强方法转化为方法执行链,
//在进行执行,其中目标方法的执行使用的是this.XXX这样就是直接调用方法,不会再获取调用方法的代理类,执行方法执行链,所以
//就造成目标方法内部调用的方法无法应用aop,可以在从容器中获取代理类,在执行代理类的目标方法,当然也可以把动态代理转化为编译时
//代理(即在编译的时候就把需要切入的方法直接编译到.class文件中)<目前不知道怎么实现[尴尬]>
//可以实现切面方法
baseService.aspectLogArgs(baseUser, i);
//可以实现切面方法
BaseServiceImpl baseServiceImpl = (BaseServiceImpl)applicationContext.getBean("baseService");
baseServiceImpl.aspectLogArgs2(baseUser, i);
//不可以实现切面方法
aspectLogArgs(baseUser, i);
//不可以实现切面方法
aspectLogArgs2(baseUser, i);
//不可以实现切面方法
this.aspectLogArgs2(baseUser, i);
}
@Override
// @BaseMethodLog
public void aspectLogArgs(BaseUser baseUser, int i) {
}
// @BaseMethodLog
public void aspectLogArgs2(BaseUser baseUser, int i) {
throw new NullPointerException();
}
}
###切面类代码
package com.xyy.springboot.configuration;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
/**
* springboot自动开启aop
*/
@Aspect
@Component
public class BaseLogAspect {
private static final Logger log = LoggerFactory.getLogger(BaseLogAspect.class);
/**
* execution:用于匹配方法执行的连接点;
* *:匹配任何数量字符;
..:匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。
+:匹配指定类型的子类型;仅能作为后缀放在类型模式后边。
java.lang.String 匹配String类型;
java.*.String 匹配java包下的任何“一级子包”下的String类型;
如匹配java.lang.String,但不匹配java.lang.ss.String
java..* 匹配java包及任何子包下的任何类型;
如匹配java.lang.String、java.lang.annotation.Annotation
java.lang.*ing 匹配任何java.lang包下的以ing结尾的类型;
java.lang.Number+ 匹配java.lang包下的任何Number的自类型;
如匹配java.lang.Integer,也匹配java.math.BigInteger
within:用于匹配指定类型内的方法执行;
this:用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;
target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;
args:用于匹配当前执行的方法传入的参数为指定类型的执行方法;
@within:用于匹配所有持有指定注解类型内的方法;
@target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;
@args:用于匹配当前执行的方法传入的参数持有指定注解的执行;
@annotation:用于匹配当前执行方法持有指定注解的方法;
bean:Spring AOP扩展的,AspectJ没有对于指示符,用于匹配特定名称的Bean对象的执行方法;
reference pointcut:表示引用其他命名切入点,只有@ApectJ风格支持,Schema风格不支持。
*/
// 只能注释在方法上
// @Pointcut("@annotation(com.xyy.springboot.configuration.BaseMethodLog)")
// 注释在类上,使方法都应用
@Pointcut("@within(com.xyy.springboot.configuration.BaseTypeLog)")
public void pointcut(){}
@Before("pointcut()")
public void logStart(JoinPoint joinPoint){
// 方法名称
String methodName = joinPoint.getSignature().getName();
// 方法参数
Object[] args = joinPoint.getArgs();
List<Object> list = Arrays.asList(args);
log.debug(methodName + "方法运行前,参数" + list.toString());
}
//如果是别的类调用这个切点,需要写全类名
//无论目标方法是否出现异常都会执行
@After("com.xyy.springboot.configuration.BaseLogAspect.pointcut()")
public void logEnd(JoinPoint joinPoint){
// 方法名称
String methodName = joinPoint.getSignature().getName();
log.debug(methodName + "方法运行后");
}
@AfterReturning(value = "pointcut()", returning = "result")
public void logReturn(JoinPoint joinPoint, Object result){
// 方法名称
String methodName = joinPoint.getSignature().getName();
if (null != result)
log.debug(methodName + "方法运行结束,结果" + result.toString());
else
log.debug(methodName + "方法运行结束");
}
@AfterThrowing(value = "pointcut()", throwing = "exception")
public void logReturn(JoinPoint joinPoint, Exception exception){
// 方法名称
String methodName = joinPoint.getSignature().getName();
log.debug(methodName + "方法运行异常", exception);
}
}