Advice通知
提示:为了理解advice,我们可以参考下面的例子:
http://www.mkyong.com/spring/spring-aop-examples-advice/
通知,制定在连接点做什么,在Sping中,他主要描述Spring围绕方法调用注入的额外的行为,Spring提供的通知类型有:
beforeadvice,AfterReturningAdvice,ThrowAdvice,MethodBeforeAdvice,这些都是Spring AOP定义的接口类,具体的动作实现需要用
户程序来完成。
public interface Advice {
}
public interface MethodBeforeAdvice extends BeforeAdvice {
void before(Method method, Object[] args, Object target) throws Throwable;
}
public interface AfterReturningAdvice extends AfterAdvice {
void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;
}
Pointcut连接点
提示:为了理解Pointcut和Advisor,我们可以参考下面的例子:
http://www.mkyong.com/spring/spring-aop-example-pointcut-advisor/
切点,其决定一个advice应该应用于哪个连接点,也就是需要插入额外处理的地方的集合,例如,被某个advice作为目标的一组方法。Spring pointcut通常意味着标示方法,可以选择一组方法调用作为pointcut,Spring提供了具体的切点来给用户使用,比如正则表达式切点 JdkRegexpMethodPointcut通过正则表达式对方法名进行匹配,其通过使用 AbstractJdkRegexpMethodPointcut中的对MethodMatcher接口的实现来完成pointcut功能.
public interface Pointcut {
/**
* Return the ClassFilter for this pointcut.
* @return the ClassFilter (never {@code null})
*/
ClassFilter getClassFilter();
/**
* Return the MethodMatcher for this pointcut.
* @return the MethodMatcher (never {@code null})
*/
MethodMatcher getMethodMatcher();
/**
* Canonical Pointcut instance that always matches.
*/
Pointcut TRUE = TruePointcut.INSTANCE;
}
AbstractRegexpMethodPointcut
public boolean matches(Method method, Class<?> targetClass) {
return ((targetClass != null && matchesPattern(targetClass.getName() + "." + method.getName())) ||
matchesPattern(method.getDeclaringClass().getName() + "." + method.getName()));
}
advisor通知器
当我们完成额外的动作设计(advice)和额外动作插入点的设计(pointcut)以后,我们需要一个对象把他们结合起来,这就是通知器 -advisor,定义应该在哪里应用哪个通知。Advisor的实现有:DefaultPointcutAdvisor他有两个属性advice和 pointcut来让我们配置advice
和pointcut。
public interface Advisor {
/**
* Return the advice part of this aspect. An advice may be an
* interceptor, a before advice, a throws advice, etc.
* @return the advice that should apply if the pointcut matches
* @see org.aopalliance.intercept.MethodInterceptor
* @see BeforeAdvice
* @see ThrowsAdvice
* @see AfterReturningAdvice
*/
Advice getAdvice();
/**
* Return whether this advice is associated with a particular instance
* (for example, creating a mixin) or shared with all instances of
* the advised class obtained from the same Spring bean factory.
* <p><b>Note that this method is not currently used by the framework.</b>
* Typical Advisor implementations always return {@code true}.
* Use singleton/prototype bean definitions or appropriate programmatic
* proxy creation to ensure that Advisors have the correct lifecycle model.
* @return whether this advice is associated with a particular target instance
*/
boolean isPerInstance();
}
public interface PointcutAdvisor extends Advisor {
/**
* Get the Pointcut that drives this advisor.
*/
Pointcut getPointcut();
}
代理对象ProxyFactoryBean
ProxyFactoryBean
@Override
public Object getObject() throws BeansException {
//初始化通知器(advisor)链
initializeAdvisorChain();
if (isSingleton()) {
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();
}
}
/**
* Create the advisor (interceptor) chain. Aadvisors that are sourced
* from a BeanFactory will be refreshed each time a new prototype instance
* is added. Interceptors added programmatically through the factory API
* are unaffected by such changes.
*/
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
if (this.advisorChainInitialized) {
return;
}
if (!ObjectUtils.isEmpty(this.interceptorNames)) {
if (this.beanFactory == null) {
throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
}
// Globals can't be last unless we specified a targetSource using the property...
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) {
if (logger.isTraceEnabled()) {
logger.trace("Configuring advisor or advice '" + name + "'");
}
if (name.endsWith(GLOBAL_SUFFIX)) {
if (!(this.beanFactory instanceof ListableBeanFactory)) {
throw new AopConfigException(
"Can only use global advisors or interceptors with a ListableBeanFactory");
}
addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
}
else {
// If we get here, we need to add a named interceptor.
// We must check if it's a singleton or prototype.
Object advice;
if (this.singleton || this.beanFactory.isSingleton(name)) {
// Add the real Advisor/Advice to the chain.
advice = this.beanFactory.getBean(name);
}
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);
}
addAdvisorOnChainCreation(advice, name);
}
}
}
this.advisorChainInitialized = true;
}
/**
* Return the singleton instance of this class's proxy object,
* lazily creating it if it hasn't been created already.
* @return the shared singleton proxy
*/
private synchronized Object getSingletonInstance() {
if (this.singletonInstance == null) {
this.targetSource = freshTargetSource();
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
// Rely on AOP infrastructure to tell us what interfaces to proxy.
Class<?> targetClass = getTargetClass();
if (targetClass == null) {
throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
}
setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
}
// Initialize the shared singleton instance.
super.setFrozen(this.freezeProxy);
this.singletonInstance = getProxy(createAopProxy());
}
return this.singletonInstance;
}
protected Object getProxy(AopProxy aopProxy) {
return aopProxy.getProxy(this.proxyClassLoader);
}
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
DefaultAopProxyFactory
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface()) {
return new JdkDynamicAopProxy(config);
}
Objenesis based extension of {@link CglibAopProxy} to create proxy instances without invoking the constructor of the class.
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}