前言
Spring AOP是大家都非常熟悉的一个概念,在Spring家族体系中扮演着举足轻重的作用。
然后Spring作为一个优秀的框架,提供了多种应用层面上代理的方式:ProxyFactoryBean、ProxyFactory、AspectJProxyFactory
注意:此处这里指的是Spring提供的应用层得方式,并不是指的底层实现方式。底层实现方式现在只有业界都熟悉的两种:JDK动态代理和CGLIB代理~
ProxyFactoryBean是将我们的AOP和IOC融合起来,而ProxyFactory 则是只能通过代码硬编码进行编写 一般都是给spring自己使用。而AspectJ是目前大家最常用的 起到集成AspectJ和Spring~~~
Spring AOP进化史:
涉及的关键类说明
ProxyConfig:为上面三个类提供配置属性
AdvisedSupport:继承ProxyConfig,实现了Advised。封装了对通知(Advise)和通知器(Advisor)的操作
ProxyCreatorSupport:继承AdvisedSupport,其帮助子类(上面三个类)创建JDK或者cglib的代理对象
Advised:可以获取拦截器和其他 advice, Advisors和代理接口
涉及到的几个关键概念
Advice:通知,定义在连接点做什么,比如我们在方法前后进行日志打印(前置通知、后置通知、环绕通知等等)
Pointcut:切点,决定advice应该作用于那个连接点,比如根据正则等规则匹配哪些方法需要增强(Pointcut 目前有getClassFilter(类匹配),getMethodMatcher(方法匹配),Pointcut TRUE (全匹配))
JoinPoint:连接点,就是spring允许你是通知(Advice)的地方,那可就真多了,基本每个方法的前、后(两者都有也行),或抛出异常是时都可以是连接点,spring只支持方法连接点。其他如AspectJ还可以让你在构造器或属性注入时都行,不过那不是咱们关注的,只要记住,和方法有关的前前后后都是连接点(通知方法里都可以获取到这个连接点,顺便获取到相关信息)。
Advisor:把pointcut和advice连接起来(可由Spring去完成,我们都交给容器管理就行,当然,你也可以手动完成)Spring的Advisor是Pointcut和Advice的配置器,它是将Advice注入程序中Pointcut位置的代码。org.springframework.aop.support.DefaultPointcutAdvisor是最通用的Advisor类
继续阅读之前,强烈建议先阅读:【小家Spring】Spring AOP原理使用的基础类打点(ProxyProcessorSupport、AopInfrastructureBean、Advised、TargetClassAware)
ProxyFactoryBean
使用Spring提供的类org.springframework.aop.framework.ProxyFactoryBean是创建AOP的最基本的方式。
它是个工厂Bean,然后我们可以自定义我们的代理实现逻辑,最终交给Spring容器管理即可。
public class ProxyFactoryBean extends ProxyCreatorSupport implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware { ... }
写个例子如下:
// 先定义一个前置通知 @Component("logMethodBeforeAdvice") public class LogMethodBeforeAdvice implements MethodBeforeAdvice { @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("this is LogMethodBeforeAdvice"); } } // 注册一个代理Bean @Bean public ProxyFactoryBean proxyFactoryBean(HelloService helloService) { ProxyFactoryBean factoryBean = new ProxyFactoryBean(); //代理的目标对象 效果同setTargetSource(@Nullable TargetSource targetSource) // 此处需要注意的是,这里如果直接new,那么该类就不能使用@Autowired之类的注入 因此建议此处还是从容器中去拿 // 因此可以写在入参上(这也是标准的写法~~) //factoryBean.setTarget(new HelloServiceImpl()); factoryBean.setTarget(helloService); // setInterfaces和setProxyInterfaces的效果是相同的。设置需要被代理的接口, // 若没有实现接口,那就会采用cglib去代理 // 需要说明的一点是:这里不设置也能正常被代理(若你没指定,Spring内部会去帮你找到所有的接口,然后全部代理上~~~~~~~~~~~~) 设置的好处是只代理指定的接口 factoryBean.setInterfaces(HelloService.class); //factoryBean.setProxyInterfaces(new Class[]{HelloService.class}); // 需要植入进目标对象的bean列表 此处需要注意:这些bean必须实现类 org.aopalliance.intercept.MethodInterceptor或 org.springframework.aop.Advisor的bean ,配置中的顺序对应调用的顺序 factoryBean.setInterceptorNames("logMethodBeforeAdvice"); // 若设置为true,强制使用cglib,默认是false的 //factoryBean.setProxyTargetClass(true); return factoryBean; } // main方法测试: public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(RootConfig.class); //expected single matching bean but found 2: helloServiceImpl,proxyFactoryBean // 如果通过类型获取,会找到两个Bean:一个我们自己的实现类、一个ProxyFactoryBean所生产的代理类 而此处我们显然是希望要生成的代理类的 因此我们只能通过名称来(或者加上@Primary) //HelloService bean = applicationContext.getBean(HelloService.class); HelloService bean = (HelloService) applicationContext.getBean("proxyFactoryBean"); bean.hello(); System.out.println(bean); //com.fsx.service.HelloServiceImpl@4e50c791 System.out.println(bean.getClass()); //class com.sun.proxy.$Proxy22 用得JDK的动态代理 // 顺便说一句:这样也是没错得。因为Spring AOP代理出来的每个代理对象,都默认实现了这个接口(它是个标记接口) // 它这个也就类似于所有的JDK代理出来的,都是Proxy的子类是一样的思想~ SpringProxy springProxy = (SpringProxy) bean; } 输出: this is LogMethodBeforeAdvice this is my method~~
由此课件,我们的HelloServiceImpl就被成功代理了。下面我们稍微看看它是怎么创建这个代理的,直接来到getObject()方法:
@Override @Nullable public Object getObject() throws BeansException { //就是根据我们配置的interceptorNames来获取对应的bean,并却转化成Advisor。 //this.advisorChainInitialized:标示是否已进行过初始化,若以初始化则不再进行初始化。 initializeAdvisorChain(); //生成代理对象时,因为Spring中有singleton类型和prototype类型这两种不同的Bean,所以要对代理对象的生成做一个区分 if (isSingleton()) { //生成singleton的代理对象,这个方法是ProxyFactoryBean生成AOPProxy代理对象的调用入口 return getSingletonInstance(); } else { if (this.targetName == null) { logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " + "Enable prototype proxies by setting the 'targetName' property."); } // 生成原型的代理对象 return newPrototypeInstance(); } } //通过读取interceptorNames将BeanFactory工厂内对应的Advice,Advisor,MethodInterceptor //通过AdvisorAdapterRegistry.wrap(Advice需要有对应的AdvisorAdapter的支持才可以转换)转换为Advisor然后加载到执行链条中 private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException { if (this.advisorChainInitialized) { return; } if (!ObjectUtils.isEmpty(this.interceptorNames)) { // Globals can't be last unless we specified a targetSource using the property... // 最后一个不能是全局的suffix *,除非我们指定了targetSource之类的 if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) && this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) { throw new AopConfigException("Target required after globals"); } // Materialize interceptor chain from bean names. for (String name : this.interceptorNames) { // 如国拦截器的名称是以*结尾的,说明它要去全局里面都搜索出来 // 全局:去自己容器以及父容器中找,类型为Advisor.class以及Interceptor.class所有的,名称是以这个名称为开头的prefix的Bean. // 最终也一样交给addAdvisorOnChainCreation(bean, name); 相当于一个批量处理吧 在特殊场景还是很有用处的 if (name.endsWith(GLOBAL_SUFFIX)) { addGlobalAdvisor((ListableBeanFactory) this.beanFactory, name.substring(0, name.length() - GLOBAL_SUFFIX.length())); } // 绝大部分情况肯定都走这里:精确匹配 else { Object advice; if (this.singleton || this.beanFactory.isSingleton(name)) { // 从容器里把这个Bean拿出来~~~~~~~~~~~~~ advice = this.beanFactory.getBean(name); } // 多例的 这里每次都是new一个新的 else { // It's a prototype Advice or Advisor: replace with a prototype. // Avoid unnecessary creation of prototype bean just for advisor chain initialization. advice = new PrototypePlaceholderAdvisor(name); } // 这个方法的作用还挺大的:将advice对象添加到通知器链中 //方法中首先会调用namedBeanToAdvisor(next)方法,将从ioc容器获取的普通对象转换成通知器Advisor对象。 详细如下: addAdvisorOnChainCreation(advice, name); } } } this.advisorChainInitialized = true; } //addAdvisorOnChainCreation private void addAdvisorOnChainCreation(Object next, String name) { // We need to convert to an Advisor if necessary so that our source reference // matches what we find from superclass interceptors. // 这里调用namedBeanToAdvisor做了一下适配:成统一的Advisor Advisor advisor = namedBeanToAdvisor(next); addAdvisor(advisor); } //namedBeanToAdvisor private Advisor namedBeanToAdvisor(Object next) { try { return this.advisorAdapterRegistry.wrap(next); } }