文章目录
文章目录
# 1 - 继承 - CGLIB (Code Generator Library)
Spring MVC
DispatcherServlet
- 调用原理
这里介绍的
AOP
继承对象 - 原理
Spring MVC - DespacterServlet
- 简化 / 模仿
package com.edut.springboot.test;
import java.util.ArrayList;
import java.util.List;
/** * /Springmvn - DispatcherServlet (简化 - 模仿) */
//=======================================
//查询服务
interface SearchService{
Object doSearch(String key ) ;
}
class DefaultSearchService implements SearchService {
@Override
public Object doSearch(String key) {
//参数校验
//数据访问
//结果处理
System.out.println("search by "+key);
return null;
}
}
//===========================================
//扩展服务
interface Interceptor{//扩展业务拦截
void doBefore() ;//{} ;jdk8 不允许 接口有 方法体
void doAfter() ;// {} ; jdk9 允许
}
class LogInterceptor implements Interceptor { //日志业务
@Override
public void doBefore() {
System.out.println("start - [Interceptor] :"+System.currentTimeMillis());
}
@Override
public void doAfter() {
System.out.println("end - [Interceptor] :"+System.currentTimeMillis());
}
}
class PermissionInterceptor implements Interceptor {//验证业务
@Override
public void doBefore() {
System.out.println("check permission - Permission[Interceptor]");
}
@Override
public void doAfter() {
}
}
//.....
//日志扩展:计时
class ChildDefaultSearchService extends DefaultSearchService {
private List<Interceptor> interceptors ;
public ChildDefaultSearchService(List<Interceptor> interceptors) {
this.interceptors = interceptors ;
}
@Override
public Object doSearch(String key) {
interceptors.forEach(i -> i.doBefore());
System.out.println("start - ChildDefault[SearchService] :"+ System.currentTimeMillis());
Object result = super.doSearch(key);//目标方法
System.out.println("end - ChildDefault[SearchService] :"+ System.currentTimeMillis());
interceptors.forEach(i -> i.doAfter());
return result;
}
}
//权限扩展:检查权限
class PermissionLogDefaultSearchService extends ChildDefaultSearchService{
public PermissionLogDefaultSearchService(List<Interceptor> interceptors) {
super(interceptors);
}
@Override
public Object doSearch(String key) {
System.out.println("check permission - PermissionLogDefault[SearchService]");
return super.doSearch(key);
}
}
public class TestExtends01 {
public static void main(String[] args) {
List<Interceptor> interceptors = new ArrayList<>() ;
interceptors.add(new PermissionInterceptor()) ;
interceptors.add(new LogInterceptor()) ;
PermissionLogDefaultSearchService service = new PermissionLogDefaultSearchService(interceptors);
service.doSearch("!!!!!! TestExtends01 !!!!!!!") ;
}
}
# 2 - 组合对象 - compose - JDK
这里介绍的
AOP
组合对象 - 原理
基于上面代码。继续业务扩展
package com.edut.springboot.test;
import java.util.ArrayList;
import java.util.List;
//============
//核心业务
interface MailService {
void send(String msg) ;
}
class DefaultMailService implements MailService {
@Override
public void send(String msg) {
System.out.println(msg);
}
}
//============================================
//扩展业务
//from class TestExtends01
//==================================
//组合对象
class ComposeMailService implements MailService {//is a
//has a
private MailService mailService ;
private List<Interceptor> interceptors ;
public ComposeMailService( MailService mailService , List<Interceptor> interceptors ) {
this.mailService = mailService;
this.interceptors = interceptors ;
}
@Override
public void send(String msg) {
interceptors.forEach(i -> i.doBefore());
mailService.send(msg); //核心业务
interceptors.forEach(i -> i.doAfter());
}
}
//======================================
public class TestCompose01 {
public static void main(String[] args) {
List<Interceptor> interceptors = new ArrayList<Interceptor>() ;
interceptors.add(new PermissionInterceptor()) ;
interceptors.add(new LogInterceptor() ) ;
ComposeMailService service = new ComposeMailService( new DefaultMailService() , interceptors);
service.send("新年快乐!");
}
}
# AspectJ - ProceedingJoinPoint 细节
- <mark>继承对象</mark> 实现 AOP ⇒
ProceedingJoinPoint.getSignature
定位到 - <mark>实现方法</mark> - <mark>组合对象</mark> 实现 AOP ⇒
ProceedingJoinPoint.getSignature
定位到 - <mark>接口方法</mark>(接口)
所以,如果 在 <mark>实现的方法上加了注解</mark>,在 <mark>组合对象实现</mark> 上,是无法获取的。
如下:
希望:组合对象方法 - AOP 获取实现上的接口
@Aspect
@Component
@Slf4j
public class SysLogAspect {
@Autowired
private SysLogService sysLogService ;
//sysLogServiceImpl
@Pointcut("bean(sysUserServiceImpl)")
public void joinPoint() {} ;
@Around("joinPoint()")
public Object around(ProceedingJoinPoint pj ) throws Throwable {
try {
long start = System.currentTimeMillis();
Object result = pj.proceed();
long end = System.currentTimeMillis() ;
saveLog(pj , end-start) ; <------ 这里 继续
↓
return result ; ↓
} catch (Throwable e) { ↓
log.error(e.getMessage()); ↓
throw e; ↓
} ↓
} ↓
private void saveLog(ProceedingJoinPoint pj, long time) throws NoSuchMethodException, SecurityException {
问题在这里(直接用注册类获取方法)-> 只能拿到接口中的方法(而注释在实现上)
↓
MethodSignature signature =(MethodSignature) pj.getSignature(); // (MethodSignature) : 提供了参数的 字符串到类型的转换
Object target = pj.getTarget();
Method method = signature.getMethod() ;
null !!!
↓
RequiredLog annotation = method.getAnnotation(RequiredLog.class);
}
}
实现类(部分)
@Service
public class SysUserServiceImpl implements SysUserService {
@RequiredLog(operation = "禁用按钮点击")
@Override
public int validById(Integer id, Integer valid) {
配置
spring:
aop:
proxy-target-class: false
# AspectJ - ProceedingJoinPoint 细节 - 总结
## 解决方法 1 : 通过 Class 类获得 Method
希望:组合对象方法 - AOP 获取实现上的接口
@Aspect
@Component
@Slf4j
public class SysLogAspect {
@Autowired
private SysLogService sysLogService ;
//sysLogServiceImpl
@Pointcut("bean(sysUserServiceImpl)")
public void joinPoint() {} ;
@Around("joinPoint()")
public Object around(ProceedingJoinPoint pj ) throws Throwable {
try {
long start = System.currentTimeMillis();
Object result = pj.proceed();
long end = System.currentTimeMillis() ;
saveLog(pj , end-start) ; <------ 这里 继续
↓
return result ; ↓
} catch (Throwable e) { ↓
log.error(e.getMessage()); ↓
throw e; ↓
} ↓
} ↓
private void saveLog(ProceedingJoinPoint pj, long time) throws NoSuchMethodException, SecurityException {
问题在这里(直接用注册类获取方法)-> 只能拿到接口中的方法(而注释在实现上)
↓
MethodSignature signature =(MethodSignature) pj.getSignature(); // (MethodSignature) : 提供了参数的 字符串到类型的转换
Object target = pj.getTarget();
通过类获取到方法(因为类指向的是 实现的类!!)
↓
//Method method = signature.getMethod() ;
Class<?> clazz = target.getClass(); // 实现 - 类
Method method = clazz.getDeclaredMethod(signature.getName() , signature.getParameterTypes());
RequiredLog annotation = method.getAnnotation(RequiredLog.class);
}
}
## 解决方法 2 : 用继承对象 AOP
修改 - 配置 (默认也是 true)
spring:
aop:
proxy-target-class: true