您的位置:首页 > 编程语言 > Java开发

《Spring技术内幕》笔记-第三章 Spring AOP的实现

2015-07-11 12:47 826 查看
AOP 概述



1, AOP:Aspect-Oriented Programming:一种模块化机制,用来描述分散在对象,类或方法中的横切关注点。从关注点中分离出横切关注点是面向切面编程的核心概念。分离关注点使解决特定领域的代码从业务逻辑中独立出来,业务逻辑代码不再有对特定领域代码的调用。特定领域的问题通过切面封装,维护,这样子分散在整个应用程序的变动就可以很好的管理。

2, Adivice通知

Advice定义连接点做什么,为切面增强提供织入接口。在Spring AOP中,主要描述Spring AOP围绕方法调用而注入的切面行为。

Spring提供了更具体的通知类型,比如BeforeAdvice,AfterAdvice等。

下面以BeforeAdvice为例:

BeforeAdvice是一个标记接口(marker interface).
public interface BeforeAdvice extends Advice {


}

[/code]

具体我们看MethodBeforeAdvice接口。
public interface MethodBeforeAdvice extends BeforeAdvice {



void before(Method method, Object[] args, Object target) throws Throwable;


}

[/code]

具体参数:method:目标方法的反射对象。args:方法执行参数。target:方法执行的对象。以CountingBeforeAdvice为例,该类完成统计被调用方法的次数。
public class CountingBeforeAdvie implements MethodBeforeAdvice{


public void before(Method method, Object[] args, Object target) throws Throwable{


count(method);

}

}

[/code]

count方法通过hashMap存储Method对象和调用次数。

2,Pointcut切点

Pointcut切点决定Advice通知作用于哪个连接点,就是说通过Pointcut来定义需要增强的方法集合。

Spring以Pointcut接口为中心,实现了一系列的类。





3,Advisor通知器

Advisor通知器定义在哪个切点Pointcut使用哪个Advice。

以Advisor的实现DefaultPointcutAdvisor为例。在DefaultPointcutAdvisor中,有两个成员变量,分别是pointCut和Advice。

public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable

[/code]

成员变量和构造方法。

private Pointcut pointcut = Pointcut.TRUE;


public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {

this.pointcut = pointcut;

setAdvice(advice);

}

[/code]

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;


}

[/code]

我们看到Pointcut引用的TRUE成员。这里使用的是单例(singleton,书中称为单件,感觉比较奇怪)。
查看TruePointcut

class TruePointcut implements Pointcut, Serializable {


public static final TruePointcut INSTANCE = new TruePointcut();


/**

 * Enforce Singleton pattern.

 */

private TruePointcut() {

}


@Override

public ClassFilter getClassFilter() {

return ClassFilter.TRUE;

}


@Override

public MethodMatcher getMethodMatcher() {

return MethodMatcher.TRUE;

}


/**

 * Required to support serialization. Replaces with canonical

 * instance on deserialization, protecting Singleton pattern.

 * Alternative to overriding {@code equals()}.

 */

private Object readResolve() {

return INSTANCE;

}


@Override

public String toString() {

return "Pointcut.TRUE";

}


}

[/code]

Spring AOP的设计与实现



1,JVM的动态代理特性

JVM的动态代理有关可以参考:http://blog.csdn.net/mergades/article/details/42173893

2,Spring AOP的设计

Spring AOP的设计核心即使动态代理模式。

3,配置ProxyFactoryBean

ProxyFactoryBean是在Spring IoC环境中创建AOP应用的底层方法,Spring通过该类完成了对AOP使用的封装。ProxyFactoryBean的配置和使用如下:

-1,定义使用的通知器Advisor,这个通知器通过Bean定义,并实现了对应的切面行为。

-2,定义ProxyFactoryBean,把它作为另一个Bean来定义,它使封装AOP功能的主要类。

-3,定义target属性。

4,ProxyFactoryBean生成AOPProxy对象。

在Spring中可以同各国ProxyFactoryBean来完成对AOP的配置目标对象和切面行为。我们可以查看其对应的属性:

public class ProxyFactoryBean extends ProxyCreatorSupport

implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware {


/**

 * This suffix in a value in an interceptor list indicates to expand globals.

 */

public static final String GLOBAL_SUFFIX = "*";



protected final Log logger = LogFactory.getLog(getClass());


private String[] interceptorNames;//已经定好的通知器


private String targetName;//目标对象


private boolean autodetectInterfaces = true;


private boolean singleton = true;


private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();


private boolean freezeProxy = false;


private transient ClassLoader proxyClassLoader = ClassUtils.getDefaultClassLoader();


private transient boolean classLoaderConfigured = false;


private transient BeanFactory beanFactory;


/** Whether the advisor chain has already been initialized */

private boolean advisorChainInitialized = false;


/** If this is a singleton, the cached singleton proxy instance */

private Object singletonInstance;

[/code]

ProxyFactoryBean依赖JDK的动态代理或者CGLIB提供的PROXY属性。

在该类中,getObject()方法对通知链进行初始化。并对Singleton和prototype类型的对象做出区分。

public Object getObject() throws BeansException {

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();

}

}

[/code]

initializeAdvisorChain()方法:

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;

}

[/code]

Spring再通过该类的getSingletonInstance()方法生成对应单例的代理对象。

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;

}

[/code]

getProxy()方法:

protected Object getProxy(AopProxy aopProxy) {

return aopProxy.getProxy(this.proxyClassLoader);

}

[/code]

Spring通过AopProxy接口把AOP代理对象的实现与框架有效地分开。

在getSingletonInstance()方法中,我们可以继续查看createAopProxy()方法,在该方法中:

protected final synchronized AopProxy createAopProxy() {

if (!this.active) {

activate();

}

return getAopProxyFactory().createAopProxy(this);

}

[/code]

在ProxyCreatorSupport中,可以看到具体的代理生成,通过AopProxyFactory实现。

protected final synchronized AopProxy createAopProxy() {

if (!this.active) {

activate();

}

return getAopProxyFactory().createAopProxy(this);

}

[/code]

构造方法:

public ProxyCreatorSupport() {

this.aopProxyFactory = new DefaultAopProxyFactory();

}

[/code]

在AopProxy代理对象的生成时,如果目标是接口类,那么适合使用JDK来生成代理对象,否砸Spring会事项CGLIB来生成目标对象的代理对象。在此类中,具体不同的代理对象的具体生成使用不同的策略JdkDynamicAopProxy和CglibProxyFactory生成,只是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);

}

return new ObjenesisCglibAopProxy(config);

}

else {

return new JdkDynamicAopProxy(config);

}

}

[/code]

5,JDK生成AopProxy代理对象

JDk通过JdkDynamicAopProxy类实现生成代理对象,该类实现了AopProxy接口。

getProxy()方法完全是基于JDK原生的动态代理来实现的。

@Override

public Object getProxy() {

return getProxy(ClassUtils.getDefaultClassLoader());

}


@Override

public Object getProxy(ClassLoader classLoader) {

if (logger.isDebugEnabled()) {

logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());

}

Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);

findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);

return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

}

[/code]

6,CGLIB生成AopProxy对象。

在Spring 4 中,已经实现ObjenesisCglibAopProxy来生成代理对象,与书中代码不同。该类实现了CglibAopProxy,我们查看其对应的getProxy方法:

@Override

public Object getProxy(ClassLoader classLoader) {

if (logger.isDebugEnabled()) {

logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());

}


try {//advised中获取target对象

Class<?> rootClass = this.advised.getTargetClass();

Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");


Class<?> proxySuperClass = rootClass;

if (ClassUtils.isCglibProxyClass(rootClass)) {

proxySuperClass = rootClass.getSuperclass();

Class<?>[] additionalInterfaces = rootClass.getInterfaces();

for (Class<?> additionalInterface : additionalInterfaces) {

this.advised.addInterface(additionalInterface);

}

}


// Validate the class, writing log messages as necessary.

validateClassIfNecessary(proxySuperClass);


// Configure CGLIB Enhancer...

Enhancer enhancer = createEnhancer();

if (classLoader != null) {

enhancer.setClassLoader(classLoader);

if (classLoader instanceof SmartClassLoader &&

((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {

enhancer.setUseCache(false);

}

}

enhancer.setSuperclass(proxySuperClass);

enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));

enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);

enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class));


Callback[] callbacks = getCallbacks(rootClass);

Class<?>[] types = new Class<?>[callbacks.length];

for (int x = 0; x < types.length; x++) {

types[x] = callbacks[x].getClass();

}

// fixedInterceptorMap only populated at this point, after getCallbacks call above

enhancer.setCallbackFilter(new ProxyCallbackFilter(

this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));

enhancer.setCallbackTypes(types);


// Generate the proxy class and create a proxy instance.

return createProxyClassAndInstance(enhancer, callbacks);

}

catch (CodeGenerationException ex) {

throw new AopConfigException("Could not generate CGLIB subclass of class [" +

this.advised.getTargetClass() + "]: " +

"Common causes of this problem include using a final class or a non-visible class",

ex);

}

catch (IllegalArgumentException ex) {

throw new AopConfigException("Could not generate CGLIB subclass of class [" +

this.advised.getTargetClass() + "]: " +

"Common causes of this problem include using a final class or a non-visible class",

ex);

}

catch (Exception ex) {

// TargetSource.getTarget() failed

throw new AopConfigException("Unexpected AOP exception", ex);

}

}

[/code]

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: