切面怎样手写实现的呢,简单版
. 定义注解:@Aspect 和 @Order
import java.lang.annotation.*;
// 标记切面类
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Aspect {
}
// 定义切面优先级(值越小,优先级越高)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Order {
int value() default Integer.MAX_VALUE;
}
. 定义通知接口
public interface Advice {
void before();
void after();
}
. 定义切点接口
import java.lang.reflect.Method;
public interface Pointcut {
boolean matches(Method method);
}
. 切面包装器(核心!)
import java.lang.annotation.Annotation;
import java.util.Arrays;
// 封装一个切面的所有信息
public class AspectWrapper implements Comparable<AspectWrapper> {
private final Object aspectInstance; // 切面实例
private final Advice advice; // 通知逻辑
private final Pointcut pointcut; // 切点
private final int order; // 优先级
public AspectWrapper(Object aspectInstance, Advice advice, Pointcut pointcut) {
this.aspectInstance = aspectInstance;
this.advice = advice;
this.pointcut = pointcut;
this.order = getAspectOrder(aspectInstance.getClass());
}
private int getAspectOrder(Class<?> clazz) {
Order orderAnno = clazz.getAnnotation(Order.class);
return orderAnno != null ? orderAnno.value() : Integer.MAX_VALUE;
}
public boolean matches(Method method) {
return pointcut.matches(method);
}
public void before() { advice.before(); }
public void after() { advice.after(); }
@Override
public int compareTo(AspectWrapper o) {
return Integer.compare(this.order, o.order); // 从小到大排序
}
}
. 多切面代理处理器(核心逻辑)
import java.lang.reflect.*;
import java.util.*;
public class MultiAspectProxy implements InvocationHandler {
private final Object target;
private final List<AspectWrapper> matchedAspects; // 匹配当前方法的切面列表
public MultiAspectProxy(Object target, List<AspectWrapper> allAspects, Method method) {
this.target = target;
// 筛选出匹配当前方法的切面,并按优先级排序
this.matchedAspects = allAspects.stream()
.filter(aspect -> aspect.matches(method))
.sorted()
.collect(Collectors.toList());
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (matchedAspects.isEmpty()) {
return method.invoke(target, args);
}
// 执行所有 before(按优先级从高到低)
for (AspectWrapper aspect : matchedAspects) {
aspect.before();
}
Object result;
try {
result = method.invoke(target, args);
} finally {
// 执行所有 after(按优先级从低到高 → 逆序)
for (int i = matchedAspects.size() - 1; i >= 0; i--) {
matchedAspects.get(i).after();
}
}
return result;
}
// 创建代理对象的工厂方法
public static Object createProxy(Object target, List<AspectWrapper> allAspects) {
Class<?>[] interfaces = target.getClass().getInterfaces();
if (interfaces.length == 0) {
throw new IllegalArgumentException("目标类必须实现至少一个接口");
}
// 为每个方法创建独立的代理处理器(实际项目中可缓存)
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
interfaces,
new MultiAspectProxy(target, allAspects, null) // 注意:简化处理
);
}
}
⚠️ 注意:上述 createProxy 方法做了简化。严格来说,应在 invoke 中动态筛选匹配当前 method 的切面。完整版见下方优化。
. 优化版:动态匹配方法的代理
Java
编辑
// 改进的 InvocationHandler
public class MultiAspectProxy implements InvocationHandler {
private final Object target;
private final List<AspectWrapper> allAspects;
public MultiAspectProxy(Object target, List<AspectWrapper> allAspects) {
this.target = target;
this.allAspects = allAspects;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 动态筛选匹配当前 method 的切面
List<AspectWrapper> matched = allAspects.stream()
.filter(aspect -> aspect.matches(method))
.sorted()
.collect(Collectors.toList());
if (matched.isEmpty()) {
return method.invoke(target, args);
}
// 执行 before(高优先级 → 低优先级)
for (AspectWrapper aspect : matched) {
aspect.before();
}
Object result;
try {
result = method.invoke(target, args);
} finally {
// 执行 after(低优先级 → 高优先级,逆序)
for (int i = matched.size() - 1; i >= 0; i--) {
matched.get(i).after();
}
}
return result;
}
public static Object createProxy(Object target, List<AspectWrapper> allAspects) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new MultiAspectProxy(target, allAspects)
);
}
}
. 实现具体切面(示例)
切面1:日志切面(高优先级)
@Aspect
@Order(1)
public class LoggingAspect implements Advice {
@Override
public void before() {
System.out.println("[LOG] 方法开始执行");
}
@Override
public void after() {
System.out.println("[LOG] 方法执行结束");
}
}
// 日志切点:匹配所有方法
public class AllMethodsPointcut implements Pointcut {
@Override
public boolean matches(Method method) {
return true;
}
}
切面2:安全切面(低优先级)
@Aspect
@Order(2)
public class SecurityAspect implements Advice {
@Override
public void before() {
System.out.println("[SECURITY] 权限检查通过");
}
@Override
public void after() {
System.out.println("[SECURITY] 清理安全上下文");
}
}
. 测试多切面
业务接口与实现
public interface UserService {
void saveUser(String name);
}
public class UserServiceImpl implements UserService {
@Override
public void saveUser(String name) {
System.out.println("保存用户: " + name);
}
}
主程序
public class MultiAspectDemo {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
// 创建切面实例
List<AspectWrapper> aspects = Arrays.asList(
new AspectWrapper(new LoggingAspect(), new LoggingAspect(), new AllMethodsPointcut()),
new AspectWrapper(new SecurityAspect(), new SecurityAspect(), new AllMethodsPointcut())
);
// 创建代理
UserService proxy = (UserService) MultiAspectProxy.createProxy(userService, aspects);
// 调用方法
proxy.saveUser("张三");
}
}
elk
浙公网安备 33010602011771号