下面我们来看看Spring的AOP的一些相关代码是怎么得到Proxy的,让我们我们先看看AOP和Spring AOP的一些基本概念:
Advice:
通知,制定在连接点做什么,在Sping中,他主要描述Spring围绕方法调用注入的额外的行为,Spring提供的通知类型有:
before advice,AfterReturningAdvice,ThrowAdvice,MethodBeforeAdvice,这些都是Spring AOP定义的接口类,具体的动作实现需要用户程序来完成。
Pointcut:
切点,其决定一个advice应该应用于哪个连接点,也就是需要插入额外处理的地方的集合,例如,被某个advice作为目标的一组方法。Spring pointcut通常意味着标示方法,可以选择一组方法调用作为pointcut,Spring提供了具体的切点来给用户使用,比如正则表达式切点 JdkRegexpMethodPointcut通过正则表达式对方法名进行匹配,其通过使用 AbstractJdkRegexpMethodPointcut中的对MethodMatcher接口的实现来完成pointcut功能:
public final boolean matches(Method method, Class targetClass) {
// TODO use target class here?
String patt = method.getDeclaringClass().getName() + "." + method.getName();
for (int i = 0; i < this.patterns.length; i++) {
// 这里是判断是否和方法名匹配的代码,当然知道true或者false
boolean matched = matches(patt, i);
if (matched) {
for (int j = 0; j < this.excludedPatterns.length; j++) {
boolean excluded = matchesExclusion(patt, j);
if(excluded) {
return false;
}
}
return true;
}
}
return false;
}
在JDKRegexpMethodPointcut中通过JDK中的正则表达式匹配来完成pointcut的最终锁定
protected boolean matches(String pattern, int patternIndex) {
Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern);
return matcher.matches();
}
Advisor:
当 我们完成额外完成的动作设计(advice)和动作插入点的设计(pointcut)以后,我们需要一个对象把他们结合起来,这就是通知器 - advisor,定义应该在哪里应用哪个通知。Advisor的实现有:DefaultPointcutAdvisor他有两个属性advice和 pointcut来让我们配置advice和pointcut。
接着我们就可以通过ProxyFactoryBean来配置我们的代理对象和方面 行为,在ProxyFactoryBean中有interceptorNames来配置已经定义好的通知器-advisor,具体的代理实现通过JDK 的Proxy或者CGLIB的技术来完成。我们可以看看具体的代码实现,在ProxyFactoryBean中我们看看怎样得到Proxy:
public Object getObject() throws BeansException {
initializeAdvisorChain();
if (isSingleton()) {
//根据定义需要生成单件的Proxy
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.");
}
//根据定义需要生成Prototype的Proxy
return newPrototypeInstance();
}
}
我们看看怎样生成单件的Proxy:
private synchronized Object getSingletonInstance() {
if (this.singletonInstance == null) {
this.targetSource = freshTargetSource();
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
// 这里设置Proxy的接口
setInterfaces(ClassUtils.getAllInterfacesForClass(this.targetSource.getTargetClass()));
}
// Eagerly initialize the shared singleton instance.
super.setFrozen(this.freezeProxy);
// 注意这里的方法会使用ProxyFactory来生成我们需要的Proxy
this.singletonInstance = getProxy(createAopProxy());
// We must listen to superclass advice change events to recache the singleton
// instance if necessary.
addListener(this);
}
return this.singletonInstance;
}
ProxyFactoryBean的父类是AdvisedSupport,Spring使用AopProxyFactory接口把AOP代理的实现与框架的其他部分分离开来;在AdvisedSupport中通过这样的方式来得到AopProxy,这里还需要AopProxyFactory的帮助 - 下面我们看到Spring为我们提供了默认的实现可以帮助我们方便的从JDK或者cglib中得到我们想要的:
protected synchronized AopProxy createAopProxy() {
if (!this.isActive) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
而在ProxyConfig中对使用的AopProxyFactory做了定义:
//这个DefaultAopProxyFactory是Spring用来生成AopProxy的地方,
//当然了它包含JDK和Cglib两种实现方式。
private transient AopProxyFactory aopProxyFactory = new DefaultAopProxyFactory();
其中在DefaultAopProxyFactory中是这样生成AopProxy的:
public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException {
if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass() ||
advisedSupport.getProxiedInterfaces().length == 0) {
if (!cglibAvailable) {
throw new AopConfigException(
"Cannot proxy target class because CGLIB2 is not available. " +
"Add CGLIB to the class path or specify proxy interfaces.");
}
// 这里使用Cglib来生成Proxy,如果target不是接口的实现的话
return CglibProxyFactory.createCglibProxy(advisedSupport);
}
else {
// 这里使用JDK来生成Proxy
return new JdkDynamicAopProxy(advisedSupport);
}
}
于是我们就可以看到其中的Proxy可以有JDK或者Cglib来生成,我们看到JdkDynamicAopProxy类和Cglib2AopProxy都实现的是AopProxy的接口,在JDK实现中我们可以看到Proxy是怎样生成的:
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
Class targetClass = this.advised.getTargetSource().getTargetClass();
logger.debug("Creating JDK dynamic proxy" +
(targetClass != null ? " for [" + targetClass.getName() + "]" : ""));
}
Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
//这里我们调用JDK Proxy来生成需要的Proxy实例
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
这样用Proxy包装target之后,对其的调用就被Proxy拦截了,ProxyFactoryBean的getObject()方法得到的实际上已经是Proxy了。
夜半待客客不至,闲敲棋子落灯花; 一个好的开源软件代码就像一卷优雅的棋谱,让我们好好享受一下吧!
博客归档
- 六月 (7)
开源的世界
- jiwenke
- China
没有评论:
发表评论