这个类位于 org.springframework.aop 包中,它的做用就是定义切面的匹配点。(简单的说就是我去切哪些类、哪些方法…) 在 Spring Aop 中匹配的点主要是 class 与 method 这两个方面, 分别为ClassFilter 与 MethodFilter正则表达式
// 由 ClassFilter 与 MethodMatcher 组成的 pointcut public interface Pointcut { // 类过滤器, 能够知道哪些类须要拦截 ClassFilter getClassFilter(); // 方法匹配器, 能够知道哪些方法须要拦截 MethodMatcher getMethodMatcher(); // 匹配全部对象的 Pointcut Pointcut TRUE = TruePointcut.INSTANCE; }
ClassFilter和MethodMatcher分别用于匹配将执行织入操做的对象以及相应的方法。
在 Spring 中主要有如下几个类,介绍以下:
一、NameMatchMethodPointcut:经过刚发名进行精确匹配的。 (PS: 其中 ClassFilter = ClassFilter.TRUE) 2、ControlFlowPointcut:根据在当前线程的堆栈信息中的方法名来决定是否切入某个方法(效率较低) 三、ComposablePointcut:组合模式的 Pointcut, 主要分红两种: 1.组合中全部都匹配算成功 2. 组合中都不匹配才算成功 4、JdkRegexpMethodPointcut:经过 正则表达式来匹配方法(PS: ClassFilter.TRUE) 5、AspectJExpressionPointcut:经过 AspectJ 包中的组件进行方法的匹配(切点表达式) 6、TransactionAttributeSourcePointcut:经过 7、TransactionAttributeSource 在 类的方法上提取事务注解的属性 @Transactional 来判断是否匹配, 提取到则说明匹配, 提取不到则说明匹配不成功 八、AnnotationJCacheOperationSource:支持JSR107的cache相关注解的支持
Advice: 建议忠告, 劝告, 通知。它其实最开始是 aopalliance 包中的一个空接口, 接口的存在主要是为了标示对应类为 Advice;spring
在Spring Aop 中 Advice 其实表示的是在 Pointcut 点上应该执行的方法。而这些方法能够在目标方法以前、以后、包裹、抛出异常等等任何地方执行。编程
public interface Advice { }
Advice: 其主要分红两类:普通advice 与Interceptor/MethodInterceptor
:缓存
Advisor 其实它就是 Pointcut 与 Advice 的组合, Advice 是执行的方法, 而要知道方法什么时候执行, 则 Advice 必需与 Pointcut 组合在一块儿, 这就诞生了 Advisor 这个类框架
1、PointcutAdvisor: 咱们在 Spring 中经常使用的 Advisor, 包含一个 Pointcut 与一个 advice; 二、DefaultPointcutAdvisor: 最经常使用的 Advisor, 在使用编程式aop时, 不少时候会将 Advice / MethodInterceptor 转换成 DefaultPointcutAdvisor; 3、NameMatchMethodPointcutAdvisor: 这个是在使用 NameMatchPointcutAdvisor时建立的 Advisor, 主要是经过 方法名来匹配是否执行 Advice; 四、DefaultBeanFactoryPointcutAdisor:自身绑定BeanFactory,须要绑定Spring的IOC容器,能够经过容器中的Advice注册的beanName来关联对应的Advice。
//声明一个aspectj切点,一张切面 JdkRegexpMethodPointcut cut = new JdkRegexpMethodPointcut(); //cut.setPattern("com.fsx.maintest.Person.run"); //它会拦截Person类下全部run的方法(没法精确到方法签名) //cut.setPattern(".*run.*");//.号匹配除"\r\n"以外的任何单个字符。*号表明零次或屡次匹配前面的字符或子表达式 因此它拦截任意包下任意类的run方法 cut.setPatterns(new String[]{".*run.*", ".*say.*"}); //能够配置多个正则表达 式... sayHi方法也会被拦截 // 声明一个通知(此处使用环绕通知 MethodInterceptor ) Advice advice = (MethodInterceptor) invocation -> { System.out.println("============>放行前拦截..."); Object obj = invocation.proceed(); System.out.println("============>放行后拦截..."); return obj; }; //切面=切点+通知 // 它还有个构造函数:DefaultPointcutAdvisor(Advice advice); 用的切面就是Pointcut.TRUE,因此若是你要指定切面,请使用本身指定的构造函数 // Pointcut.TRUE:表示啥都返回true,也就是说这个切面做用于全部的方法上/全部的方法 // addAdvice();方法最终内部都是被包装成一个 `DefaultPointcutAdvisor`,且使用的是Pointcut.TRUE切面,所以须要注意这些区别 至关于new DefaultPointcutAdvisor(Pointcut.TRUE,advice); Advisor advisor = new DefaultPointcutAdvisor(cut, advice);
承载一个代理对象须要的必要信息:如相关目标类、Advice、Advisoride
// 这个 Advised 接口的实现着主要是代理生成的对象与AdvisedSupport (Advised的支持器) public interface Advised extends TargetClassAware { // 这个 frozen 决定是否 AdvisedSupport 里面配置的信息是否改变,设置为true,那么一旦代理对象生成的各项代理信息配置完成,不允许进行更改 boolean isFrozen(); //若是该值为true,那么就是用CGLIB对对象进行代理,默认值为false boolean isProxyTargetClass(); // 返回代理的接口 Class<?>[] getProxiedInterfaces(); // 判断这个接口是不是被代理的接口 boolean isInterfaceProxied(Class<?> intf); // 设置代理的目标对象 void setTargetSource(TargetSource targetSource); // 获取代理的对象 TargetSource getTargetSource(); // 判断是否须要将代理的对象暴露到 ThreadLocal中,若是目标对象但愿获取代理对象,则能够经过AopContext.currentProxy()取得默认值false void setExposeProxy(boolean exposeProxy); // 返回是否应该暴露代理对象 boolean isExposeProxy(); // 设置 Advisor 是否已经在前面过滤过是否匹配 Pointcut (极少用到) void setPreFiltered(boolean preFiltered); // 获取 Advisor 是否已经在前面过滤过是否匹配 Pointcut (极少用到) boolean isPreFiltered(); // 获取全部的 Advisor Advisor[] getAdvisors(); // 增长 Advisor 到链表的最后 void addAdvisor(Advisor advisor) throws AopConfigException; // 在指定位置增长 Advisor void addAdvisor(int pos, Advisor advisor) throws AopConfigException; // 删除指定的 Advisor boolean removeAdvisor(Advisor advisor); // 删除指定位置的 Advisor void removeAdvisor(int index) throws AopConfigException; // 返回 Advisor 所在位置的index int indexOf(Advisor advisor); // 将指定的两个 Advisor 进行替换 boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException; // 增长 Advice <- 这个Advice将会包裹成 DefaultPointcutAdvisor void addAdvice(Advice advice) throws AopConfigException; // 在指定 index 增长 Advice <- 这个Advice将会包裹成 DefaultPointcutAdvisor void addAdvice(int pos, Advice advice) throws AopConfigException; // 删除给定的 Advice boolean removeAdvice(Advice advice); // 获取 Advice 的索引位置 int indexOf(Advice advice); // 将 ProxyConfig 经过 String 形式返回 String toProxyConfigString(); }
TargetSource(目标源)是被代理的target(目标对象)实例的来源。函数
public interface TargetSource extends TargetClassAware { //目标对象类型 Class<?> getTargetClass(); // 这个方法用户返回当前bean是否为静态的,好比常见的单例bean就是静态的,而prototype就是动态的, // 这里这个方法的主要做用是,对于静态的bean,spring是会对其进行缓存的,在屡次使用TargetSource // 获取目标bean对象的时候,其获取的老是同一个对象,经过这种方式提升效率 boolean isStatic(); //获取目标对象 Object getTarget() throws Exception; // Spring在完目标bean以后会调用这个方法释放目标bean对象,对于一些须要池化的对象,这个方法是必须 // 要实现的,这个方法默认不进行任何处理 void releaseTarget(Object target) throws Exception; }
TargetSource最主要的特性:每次方法调用都会触发TargetSource的getTarget()的方法,该方法会从TargetSource中获取类中具体的目标对象;this
在一般状况下,不管是使用setTarget(),仍是经过setTargetName()方法等设置的目标对象,在框架内部都会经过一个TargetSource实现类对这个设置的目标对象进行封装,框架内部会以统一的方式处理调用链终点的目标对象。spa
public void setTarget(Object target) { setTargetSource(new SingletonTargetSource(target)); }
TargetSource的实现类:prototype
(1)、SingletonTargetSource
在经过ProxyFactoryBean的setTarget()方法设置目标对象就是使用SingletonTargetSource,ProxyFactoryBean内部会自行使用一个SingletonTargetSource对设置的目标对象进行封装。
public class SingletonTargetSource implements TargetSource, Serializable { /** use serialVersionUID from Spring 1.2 for interoperability */ private static final long serialVersionUID = 9031246629662423738L; /** Target cached and invoked using reflection */ private final Object target; /** * Create a new SingletonTargetSource for the given target. * @param target the target object */ public SingletonTargetSource(Object target) { Assert.notNull(target, "Target object must not be null"); this.target = target; } @Override public Class<?> getTargetClass() { return this.target.getClass(); } @Override public Object getTarget() { return this.target; } @Override public void releaseTarget(Object target) { // nothing to do } @Override public boolean isStatic() { return true; } /** * Two invoker interceptors are equal if they have the same target or if the * targets or the targets are equal. */ @Override public boolean equals(Object other) { if (this == other) { return true; } if (!(other instanceof SingletonTargetSource)) { return false; } SingletonTargetSource otherTargetSource = (SingletonTargetSource) other; return this.target.equals(otherTargetSource.target); } /** * SingletonTargetSource uses the hash code of the target object. */ @Override public int hashCode() { return this.target.hashCode(); } @Override public String toString() { return "SingletonTargetSource for target object [" + ObjectUtils.identityToString(this.target) + "]"; } }
(2)、PrototypeTargetSource
每次getTarget()将生成prototype类型的bean,即其生成的bean并非单例的,于是使用这个类型的TargetSource时须要注意,封装的目标bean必须是prototype类型的。PrototypeTargetSource继承了AbstractBeanFactoryBasedTargetSource拥有了建立bean的能力。
public class PrototypeTargetSource extends AbstractPrototypeBasedTargetSource { @Override public Object getTarget() throws BeansException { return newPrototypeInstance(); } @Override public void releaseTarget(Object target) { destroyPrototypeInstance(target); } @Override public String toString() { return "PrototypeTargetSource for target bean with name '" + getTargetBeanName() + "'"; } } public abstract class AbstractPrototypeBasedTargetSource extends AbstractBeanFactoryBasedTargetSource { @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { super.setBeanFactory(beanFactory); // Check whether the target bean is defined as prototype. if (!beanFactory.isPrototype(getTargetBeanName())) { throw new BeanDefinitionStoreException( "Cannot use prototype-based TargetSource against non-prototype bean with name '" + getTargetBeanName() + "': instances would not be independent"); } } /** * Subclasses should call this method to create a new prototype instance. * @throws BeansException if bean creation failed */ protected Object newPrototypeInstance() throws BeansException { if (logger.isDebugEnabled()) { logger.debug("Creating new instance of bean '" + getTargetBeanName() + "'"); } //使用容器建立一个bean,若是getTargetBeanName()是prototype的,则target目标对象也是prototype的 return getBeanFactory().getBean(getTargetBeanName()); } /** * Subclasses should call this method to destroy an obsolete prototype instance. * @param target the bean instance to destroy */ protected void destroyPrototypeInstance(Object target) { if (logger.isDebugEnabled()) { logger.debug("Destroying instance of bean '" + getTargetBeanName() + "'"); } if (getBeanFactory() instanceof ConfigurableBeanFactory) { ((ConfigurableBeanFactory) getBeanFactory()).destroyBean(getTargetBeanName(), target); } else if (target instanceof DisposableBean) { try { ((DisposableBean) target).destroy(); } catch (Throwable ex) { logger.warn("Destroy method on bean with name '" + getTargetBeanName() + "' threw an exception", ex); } } } //--------------------------------------------------------------------- // Serialization support //--------------------------------------------------------------------- private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { throw new NotSerializableException("A prototype-based TargetSource itself is not deserializable - " + "just a disconnected SingletonTargetSource or EmptyTargetSource is"); } /** * Replaces this object with a SingletonTargetSource on serialization. * Protected as otherwise it won't be invoked for subclasses. * (The {@code writeReplace()} method must be visible to the class * being serialized.) * <p>With this implementation of this method, there is no need to mark * non-serializable fields in this class or subclasses as transient. */ protected Object writeReplace() throws ObjectStreamException { if (logger.isDebugEnabled()) { logger.debug("Disconnecting TargetSource [" + this + "]"); } try { // Create disconnected SingletonTargetSource/EmptyTargetSource. Object target = getTarget(); return (target != null ? new SingletonTargetSource(target) : EmptyTargetSource.forClass(getTargetClass())); } catch (Exception ex) { String msg = "Cannot get target for disconnecting TargetSource [" + this + "]"; logger.error(msg, ex); throw new NotSerializableException(msg + ": " + ex); } } }