AOP存在的主要目的就是为了解耦复杂业务,同时能够使业务具备较强的扩展性。
AOP面向切面的基本概念
Spring AOP 实现
实现一个用于记录日志的AOP
首先定义一个标记切入点、连接点的注解MyLog
1 2 3 4 5
| @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) public @interface MyLog { }
|
定义实际切入的Advice通知
- 需要增加注解
@Aspect
- 定义切入点:
@Pointcut("@annotation(com.example.aopdemo.aop.anno.MyLog)")
- 定义通知:
@After、 @Before 、@Around
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| @Aspect @Component public class LogAspect { @Pointcut("@annotation(com.example.aopdemo.aop.anno.MyLog)") public void pointCut() {}
@After("pointCut()") public void recordRequestParam(JoinPoint joinPoint) { for (Object s : joinPoint.getArgs()) { System.out.println("after advice : " + s); } }
@Before("pointCut()") public void startRecord(JoinPoint joinPoint) { for (Object s : joinPoint.getArgs()) { System.out.println("before advice : " + s); } }
@Around("pointCut()") public Object aroundRecord(ProceedingJoinPoint pjp) throws Throwable { for (Object s : pjp.getArgs()) { System.out.println("around advice : " + s); } return pjp.proceed(); } }
|
在代理目标上加入切入点
1 2 3 4 5 6 7 8 9
| @RestController public class MockController { @RequestMapping("/mock") @MyLog public String helloAop(@RequestParam String key) { System.out.println("do something..."); return "hello world"; } }
|
测试Test
1 2 3 4 5 6 7 8 9 10
| @SpringBootTest public class MockControllerTest { @Autowired MockController mockController;
@Test void helloAop() { mockController.helloAop("aop"); } }
|

实现一个类似登录验证的demo
1 2 3 4 5
| @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) public @interface LoginAnno { }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| @Aspect @Component public class LoginAspect {
private boolean res = true;
@Pointcut("@annotation(com.example.aopdemo.aop.anno.LoginAnno)") public void pointCut() {}
@After("pointCut()") public void adviceBoolean(JoinPoint joinPoint){ System.out.println("after : " + res); }
@Before("pointCut()") public void checkLogin(JoinPoint joinPoint){ List<Object> param = new ArrayList<>(); for (Object s: joinPoint.getArgs()){ param.add(s); } res = param.get(0).equals("admin") && param.get(1).equals("124"); System.out.println("before check login....."); }
@Around("pointCut()") public Object around(ProceedingJoinPoint pjp) throws Throwable { for (Object s : pjp.getArgs()){ System.out.println(s); } return pjp.proceed(); } }
|
1 2 3 4 5 6 7 8 9 10 11
| @RestController public class ServiceController {
@RequestMapping("/service") @LoginAnno public String service(@RequestParam String username, @RequestParam String password) { System.out.println("验证成功"); return "service"; } }
|
JDK动态代理实现
JDK动态代理要求被代理对象需要实现一个接口。
我们这里假设我们有一个Smms服务需要增强,其主要服务使发送验证码的消息。
SmmsService
1 2 3
| interface SmmsService{ String sendMessage(String message); }
|
SmmsServiceImpl
1 2 3 4 5 6 7
| class SmmsServiceImpl implements SmmsService{ @Override public String sendMessage(String message) { System.out.println(message); return message; } }
|
动态代理类 SmmsServiceProxy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class SmmsServiceProxy extends InvocationHandler { private final Object target; public SmmsServiceProxy(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before execute"); Object res = method.invoke(target, args); System.out.println("after execute"); return res; } }
|
生成动态代理对象的工厂 JdkProxyFactory
1 2 3 4 5
| class JdkProxyFactory { public static Object getProxy(Object target) { return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new SmmsServiceProxy(target)); } }
|
实际使用
1 2 3 4 5 6
| public class DynamicProxys { public static void main(String[] args) { SmmsService proxy = (SmmsService) JdkProxyFactory.getProxy(new SmmsServiceImpl()); proxy.sendMessage("hello"); } }
|
