@RestControllerEndpoint(id = "proxy") @RequiredArgsConstructor public class ProxyMetaDefinitionControllerEndPoint { private final ProxyMetaDefinitionRepository proxyMetaDefinitionRepository; @GetMapping("listMeta") public List<ProxyMetaDefinition> getProxyMetaDefinitions(){ return proxyMetaDefinitionRepository.getProxyMetaDefinitions(); } @GetMapping("{id}") public ProxyMetaDefinition getProxyMetaDefinition(@PathVariable("id") String proxyMetaDefinitionId){ return proxyMetaDefinitionRepository.getProxyMetaDefinition(proxyMetaDefinitionId); } @PostMapping("save") public String save(@RequestBody ProxyMetaDefinition definition){ try { proxyMetaDefinitionRepository.save(definition); return "success"; } catch (Exception e) { } return "fail"; } @PostMapping("delete/{id}") public String delete(@PathVariable("id")String proxyMetaDefinitionId){ try { proxyMetaDefinitionRepository.delete(proxyMetaDefinitionId); return "success"; } catch (Exception e) { } return "fail"; } }2、利用事件监听机制捕获安装或者卸载插件
@RequiredArgsConstructor public class ProxyMetaDefinitionChangeListener { private final AopPluginFactory aopPluginFactory; @EventListener public void listener(ProxyMetaDefinitionChangeEvent proxyMetaDefinitionChangeEvent){ ProxyMetaInfo proxyMetaInfo = aopPluginFactory.getProxyMetaInfo(proxyMetaDefinitionChangeEvent.getProxyMetaDefinition()); switch (proxyMetaDefinitionChangeEvent.getOperateEventEnum()){ case ADD: aopPluginFactory.installPlugin(proxyMetaInfo); break; case DEL: aopPluginFactory.uninstallPlugin(proxyMetaInfo.getId()); break; } } }3、安装插件
public void installPlugin(ProxyMetaInfo proxyMetaInfo){ if(StringUtils.isEmpty(proxyMetaInfo.getId())){ proxyMetaInfo.setId(proxyMetaInfo.getProxyUrl() + SPIILT + proxyMetaInfo.getProxyClassName()); } AopUtil.registerProxy(defaultListableBeanFactory,proxyMetaInfo); }4、安装插件核心实现
public static void registerProxy(DefaultListableBeanFactory beanFactory,ProxyMetaInfo proxyMetaInfo){ AspectJExpressionPointcutAdvisor advisor = getAspectJExpressionPointcutAdvisor(beanFactory, proxyMetaInfo); addOrDelAdvice(beanFactory,OperateEventEnum.ADD,advisor); } private static AspectJExpressionPointcutAdvisor getAspectJExpressionPointcutAdvisor(DefaultListableBeanFactory beanFactory, ProxyMetaInfo proxyMetaInfo) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(); GenericBeanDefinition beanDefinition = (GenericBeanDefinition) builder.getBeanDefinition(); beanDefinition.setBeanClass(AspectJExpressionPointcutAdvisor.class); AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor(); advisor.setExpression(proxyMetaInfo.getPointcut()); advisor.setAdvice(Objects.requireNonNull(getMethodInterceptor(proxyMetaInfo.getProxyUrl(), proxyMetaInfo.getProxyClassName()))); beanDefinition.setInstanceSupplier((Supplier<AspectJExpressionPointcutAdvisor>) () -> advisor); beanFactory.registerBeanDefinition(PROXY_PLUGIN_PREFIX + proxyMetaInfo.getId(),beanDefinition); return advisor; }5、卸载插件
public void uninstallPlugin(String id){ String beanName = PROXY_PLUGIN_PREFIX + id; if(defaultListableBeanFactory.containsBean(beanName)){ AopUtil.destoryProxy(defaultListableBeanFactory,id); }else{ throw new NoSuchElementException("Plugin not found: " + id); } }6、卸载插件核心实现
public static void destoryProxy(DefaultListableBeanFactory beanFactory,String id){ String beanName = PROXY_PLUGIN_PREFIX + id; if(beanFactory.containsBean(beanName)){ AspectJExpressionPointcutAdvisor advisor = beanFactory.getBean(beanName,AspectJExpressionPointcutAdvisor.class); addOrDelAdvice(beanFactory,OperateEventEnum.DEL,advisor); beanFactory.destroyBean(beanFactory.getBean(beanName)); } }7、操作advice实现
public static void addOrDelAdvice(DefaultListableBeanFactory beanFactory, OperateEventEnum operateEventEnum,AspectJExpressionPointcutAdvisor advisor){ AspectJExpressionPointcut pointcut = (AspectJExpressionPointcut) advisor.getPointcut(); for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) { Object bean = beanFactory.getBean(beanDefinitionName); if(!(bean instanceof Advised)){ if(operateEventEnum == OperateEventEnum.ADD){ buildCandidateAdvised(beanFactory,advisor,bean,beanDefinitionName); } continue; } Advised advisedBean = (Advised) bean; boolean isFindMatchAdvised = findMatchAdvised(advisedBean.getClass(),pointcut); if(operateEventEnum == OperateEventEnum.DEL){ if(isFindMatchAdvised){ advisedBean.removeAdvice(advisor.getAdvice()); log.info("########################################## Remove Advice -->【{}】 For Bean -->【{}】 SUCCESS !",advisor.getAdvice().getClass().getName(),bean.getClass().getName()); } }else if(operateEventEnum == OperateEventEnum.ADD){ if(isFindMatchAdvised){ advisedBean.addAdvice(advisor.getAdvice()); log.info("########################################## Add Advice -->【{}】 For Bean -->【{}】 SUCCESS !",advisor.getAdvice().getClass().getName(),bean.getClass().getName()); } } } }热插拔AOP演示示例
@Service @Slf4j public class HelloService implements BeanNameAware, BeanFactoryAware { private BeanFactory beanFactory; private String beanName; @SneakyThrows public String sayHello(String message) { Object bean = beanFactory.getBean(beanName); log.info("============================ {} is Advised : {}",bean, bean instanceof Advised); TimeUnit.SECONDS.sleep(new Random().nextInt(3)); log.info("============================ hello:{}",message); return "hello:" + message; } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } @Override public void setBeanName(String name) { this.beanName = name; } }2、创建一个controller
@RestController @RequestMapping("hello") @RequiredArgsConstructor public class HelloController { private final HelloService helloService; @GetMapping("{message}") public String sayHello(@PathVariable("message")String message){ return helloService.sayHello(message); } }3、准备一个日志切面jar
@Slf4j public class LogMethodInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { Object result; try { result = invocation.proceed(); } finally { log.info(">>>>>>>>>>>>>>>>>>>>>>>>TargetClass:【{}】,method:【{}】,args:【{}】",invocation.getThis().getClass().getName(),invocation.getMethod().getName(), Arrays.toString(invocation.getArguments())); } return result; } }4、测试
再次观察控制台
出现了切面日志信息,说明代理生效
########################################## Remove Advice -->【com.github.lybgeek.interceptor.LogMethodInterceptor】 For Bean -->【com.github.lybgeek.aop.test.hello.service.HelloService$$EnhancerBySpringCGLIB$$7bc75aa3】 SUCCESS !此时浏览器访问:http://localhost:8080/hello/zhangsan