Spring-aop-ProxyFactoryBeanソースコード分析
本編を読む前に、まず読んでください.
http://wangxinchun.iteye.com/blog/2079024,繰り返しのロジック,本編では解析を行わない~
スプリングフレームワークには鮮明な特徴があり、一般的なサービスにはプログラミング式と構成式の2つの実現があります.
プログラミング方式の使用は往々にして明らかであるが、機能は相対的に弱く、使用は簡潔ではない.構成式は往々にしてspringのiocフレームワークと結合することができ、より緩やかでより強力な機能を提供し、springフレームワークがすべての面で表現されていることを兼ね備えている.
ProxyFactoryがAOPブロッキングを実現する方式に対してProxyFactoryBean 構成によってすべてのブロック機能を実現します.
使用case:
ビジネスクラス
拡張(Advice,Interceptor)
その他の補助ツールコード:
アプリケーションContext.xml構成
テスト:
出力:
BeforeAdvice1.before() execute
BeforeAdvice1.before() execute
com.qunar.vo.User@111b910
AfterAdvice2.afterReturning() execute
AfterAdvice1.afterReturning() execute
概要:
ProxyFactoryBeanは継承システムにおいてProxyFactoryとあまり差はありませんが、ProxyFactoryBeanはBeanFactoryAware BeanClassLoaderAware FactoryBeanの3つのインターフェースを実現しています.IOCコンテナに詳しいとProxyFactoryBeanとIOCコンテナが融合していることがわかります.ProxyFactoryBeanはIOCコンテナの配置を借りているのですが、Advice拡張オブジェクトとtargetオブジェクトを見つけます.
次にソースプロファイルに入ります
http://wangxinchun.iteye.com/blog/2079024,繰り返しのロジック,本編では解析を行わない~
スプリングフレームワークには鮮明な特徴があり、一般的なサービスにはプログラミング式と構成式の2つの実現があります.
プログラミング方式の使用は往々にして明らかであるが、機能は相対的に弱く、使用は簡潔ではない.構成式は往々にしてspringのiocフレームワークと結合することができ、より緩やかでより強力な機能を提供し、springフレームワークがすべての面で表現されていることを兼ね備えている.
ProxyFactoryがAOPブロッキングを実現する方式に対してProxyFactoryBean 構成によってすべてのブロック機能を実現します.
使用case:
ビジネスクラス
public interface LoginService {
public boolean login(User user);
}
public class LoginServiceImpl implements LoginService {
public boolean login(User user) {
System.out.println(user);
if (user == null) {
return false;
} else if (user.getUsername() == "xinchun.wang" && user.getPassword() == "123456") {
return true;
}
return false;
}
}
拡張(Advice,Interceptor)
public class AfterAdvice1 implements AfterReturningAdvice{
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
System.out.println("AfterAdvice1.afterReturning() execute ");
}
}
public class AfterAdvice2 implements AfterReturningAdvice{
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
System.out.println("AfterAdvice2.afterReturning() execute ");
}
}
public class BeforeAdvice1 implements MethodBeforeAdvice{
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("BeforeAdvice1.before() execute ");
}
}
public class BeforeAdvice2 implements MethodBeforeAdvice{
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("BeforeAdvice2.before() execute ");
}
}
その他の補助ツールコード:
public class BeanFactoryUtils implements BeanFactoryAware{
private static BeanFactory beanFactory;
public static BeanFactoryUtils getInstance(){
return (BeanFactoryUtils)beanFactory.getBean("factoryUtil");
}
public void setBeanFactory(BeanFactory bf) throws BeansException {
beanFactory = bf;
}
public BeanFactory getBeanFactory() {
return beanFactory;
}
}
アプリケーションContext.xml構成
<bean id="afterAdvice1" class="com.qunar.service.AfterAdvice1" />
<bean id="afterAdvice2" class="com.qunar.service.AfterAdvice2" />
<bean id="beforeAdvice1" class="com.qunar.service.BeforeAdvice1" />
<bean id="beforeAdvice2" class="com.qunar.service.BeforeAdvice1" />
<bean id="loginService" class="com.qunar.service.LoginServiceImpl"/>
<bean id="factoryUtil" class=" com.qunar.util.BeanFactoryUtils" />
<bean id="loginServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- -->
<property name="proxyInterfaces">
<value> com.qunar.service.LoginService</value>
</property>
<!-- ProxyFactoryBean -->
<property name="target">
<ref bean="loginService" />
</property>
<!-- Advice -->
<property name="interceptorNames">
<list>
<value>afterAdvice1</value>
<value>afterAdvice2</value>
<value>beforeAdvice1</value>
<value>beforeAdvice2</value>
</list>
</property>
</bean>
テスト:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath*:META-INF/spring/applicationContext.xml"})
public class LoginServiceImplTest {
@Test
public void proxyLoginTest() {
LoginService loginService = (LoginService)BeanFactoryUtils.getInstance().getBeanFactory().getBean("loginServiceProxy");
loginService.login(new User("xinchun.wang","123456"));
}
}
出力:
BeforeAdvice1.before() execute
BeforeAdvice1.before() execute
com.qunar.vo.User@111b910
AfterAdvice2.afterReturning() execute
AfterAdvice1.afterReturning() execute
概要:
ProxyFactoryBeanは継承システムにおいてProxyFactoryとあまり差はありませんが、ProxyFactoryBeanはBeanFactoryAware BeanClassLoaderAware FactoryBeanの3つのインターフェースを実現しています.IOCコンテナに詳しいとProxyFactoryBeanとIOCコンテナが融合していることがわかります.ProxyFactoryBeanはIOCコンテナの配置を借りているのですが、Advice拡張オブジェクトとtargetオブジェクトを見つけます.
次にソースプロファイルに入ります
public class ProxyFactoryBean extends ProxyCreatorSupport
implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware {
/**
* interceptor
*/
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;
// ProxyFactory , 。 。
private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
private boolean freezeProxy = false;
private transient ClassLoader proxyClassLoader = ClassUtils.getDefaultClassLoader();
private transient boolean classLoaderConfigured = false;
//IOC
private transient BeanFactory beanFactory;
/** Whether the advisor chain has already been initialized */
private boolean advisorChainInitialized = false;
/** ,singletonInstance */
private Object singletonInstance;
/**
* , , cglib2 。
*/
public void setProxyInterfaces(Class[] proxyInterfaces) throws ClassNotFoundException {
setInterfaces(proxyInterfaces);
}
/**
interceptorNames , IOC 。
interceptorNames Interceptor, Advisor or Advice,
IOC , Advice Advisor,
SingletonTargetSource , target targetSource targetName
, interceptorNames Advice/Advisor bean names.*/
public void setInterceptorNames(String[] interceptorNames) {
this.interceptorNames = interceptorNames;
}
/**
* targetname
*/
public void setTargetName(String targetName) {
this.targetName = targetName;
}
/**
* , true, false, cglib 。
*/
public void setAutodetectInterfaces(boolean autodetectInterfaces) {
this.autodetectInterfaces = autodetectInterfaces;
}
/**
*
*/
public void setSingleton(boolean singleton) {
this.singleton = singleton;
}
/**
*you know。。。
*/
public void setAdvisorAdapterRegistry(AdvisorAdapterRegistry advisorAdapterRegistry) {
this.advisorAdapterRegistry = advisorAdapterRegistry;
}
@Override
public void setFrozen(boolean frozen) {
this.freezeProxy = frozen;
}
public void setProxyClassLoader(ClassLoader classLoader) {
this.proxyClassLoader = classLoader;
this.classLoaderConfigured = (classLoader != null);
}
public void setBeanClassLoader(ClassLoader classLoader) {
if (!this.classLoaderConfigured) {
this.proxyClassLoader = classLoader;
}
}
// beanfacotry 。
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
checkInterceptorNames();
}
/**
* , !!!
*/
public Object getObject() throws BeansException {
initializeAdvisorChain(); // advice Advisor
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(); //
}
}
public Class<?> getObjectType() {
synchronized (this) {
if (this.singletonInstance != null) {
return this.singletonInstance.getClass();
}
}
Class[] ifcs = getProxiedInterfaces();
if (ifcs.length == 1) {
return ifcs[0];
}
else if (ifcs.length > 1) {
return createCompositeInterface(ifcs);
}
else if (this.targetName != null && this.beanFactory != null) {
return this.beanFactory.getType(this.targetName);
}
else {
return getTargetClass();
}
}
public boolean isSingleton() {
return this.singleton;
}
/**
* , ,
*/
protected Class createCompositeInterface(Class[] interfaces) {
return ClassUtils.createCompositeInterface(interfaces, this.proxyClassLoader);
}
/**
*
*/
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()); // createAopProxy AopProxyFactory aop ( ProxyFactory )
}
return this.singletonInstance;
}
//
private synchronized Object newPrototypeInstance() {
if (logger.isTraceEnabled()) {
logger.trace("Creating copy of prototype ProxyFactoryBean config: " + this);
}
// copy ProxyFacotryBean getAopProxyFactory ,
ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory());
// The copy needs a fresh advisor chain, and a fresh TargetSource.
TargetSource targetSource = freshTargetSource();
copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain()); // copy
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
// Rely on AOP infrastructure to tell us what interfaces to proxy.
copy.setInterfaces(
ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass(), this.proxyClassLoader));
}
copy.setFrozen(this.freezeProxy);
if (logger.isTraceEnabled()) {
logger.trace("Using ProxyCreatorSupport copy: " + copy);
}
return getProxy(copy.createAopProxy());
}
/**
* AopProxy jdk cglib
*/
protected Object getProxy(AopProxy aopProxy) {
return aopProxy.getProxy(this.proxyClassLoader);
}
/**
* interceptorNames advice advisor , target
*/
private void checkInterceptorNames() {
if (!ObjectUtils.isEmpty(this.interceptorNames)) {
String finalName = this.interceptorNames[this.interceptorNames.length - 1];
if (this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
// tareget
if (!finalName.endsWith(GLOBAL_SUFFIX) && !isNamedBeanAnAdvisorOrAdvice(finalName)) {
// finalName
this.targetName = finalName;
if (logger.isDebugEnabled()) {
logger.debug("Bean with name '" + finalName + "' concluding interceptor chain " +
"is not an advisor class: treating it as a target or TargetSource");
}
String[] newNames = new String[this.interceptorNames.length - 1];
System.arraycopy(this.interceptorNames, 0, newNames, 0, newNames.length);
this.interceptorNames = newNames;
}
}
}
}
/**
* Advisor Advice
*/
private boolean isNamedBeanAnAdvisorOrAdvice(String beanName) {
Class namedBeanClass = this.beanFactory.getType(beanName);
if (namedBeanClass != null) {
return (Advisor.class.isAssignableFrom(namedBeanClass) || Advice.class.isAssignableFrom(namedBeanClass));
}
// Treat it as an target bean if we can't tell.
if (logger.isDebugEnabled()) {
logger.debug("Could not determine type of bean with name '" + beanName +
"' - assuming it is neither an Advisor nor an Advice");
}
return false;
}
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));
}
// , targetSource targetName
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");
}
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())); // advisor
}
else {
//
Object advice;
if (this.singleton || this.beanFactory.isSingleton(name)) {
// , Advisor/Advice to the chain.
advice = this.beanFactory.getBean(name);
}
else {
// advisor
advice = new PrototypePlaceholderAdvisor(name);
}
addAdvisorOnChainCreation(advice, name);
}
}
}
this.advisorChainInitialized = true;
}
/**
* advisor , prototype ,
*/
private List<Advisor> freshAdvisorChain() {
Advisor[] advisors = getAdvisors();
List<Advisor> freshAdvisors = new ArrayList<Advisor>(advisors.length);
for (Advisor advisor : advisors) {
if (advisor instanceof PrototypePlaceholderAdvisor) { // advisor
PrototypePlaceholderAdvisor pa = (PrototypePlaceholderAdvisor) advisor;
if (logger.isDebugEnabled()) {
logger.debug("Refreshing bean named '" + pa.getBeanName() + "'");
}
if (this.beanFactory == null) {
throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
"- cannot resolve prototype advisor '" + pa.getBeanName() + "'");
}
Object bean = this.beanFactory.getBean(pa.getBeanName());
Advisor refreshedAdvisor = namedBeanToAdvisor(bean);
freshAdvisors.add(refreshedAdvisor);
}
else {
// Add the shared instance.
freshAdvisors.add(advisor);
}
}
return freshAdvisors;
}
/**
*/
private void addGlobalAdvisor(ListableBeanFactory beanFactory, String prefix) {
String[] globalAdvisorNames =
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Advisor.class); // Advisor
String[] globalInterceptorNames =
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Interceptor.class); // Interceptor
List<Object> beans = new ArrayList<Object>(globalAdvisorNames.length + globalInterceptorNames.length);
Map<Object, String> names = new HashMap<Object, String>(beans.size());
for (String name : globalAdvisorNames) {
Object bean = beanFactory.getBean(name);
beans.add(bean);
names.put(bean, name);
}
for (String name : globalInterceptorNames) {
Object bean = beanFactory.getBean(name);
beans.add(bean);
names.put(bean, name);
}
OrderComparator.sort(beans);
for (Object bean : beans) {
String name = names.get(bean);
if (name.startsWith(prefix)) {
addAdvisorOnChainCreation(bean, name);
}
}
}
/**
* advice , Advice
*/
private void addAdvisorOnChainCreation(Object next, String name) {
Advisor advisor = namedBeanToAdvisor(next);
if (logger.isTraceEnabled()) {
logger.trace("Adding advisor with name '" + name + "'");
}
addAdvisor(advisor);
}
private TargetSource freshTargetSource() {
if (this.targetName == null) {
if (logger.isTraceEnabled()) {
logger.trace("Not refreshing target: Bean name not specified in 'interceptorNames'.");
}
return this.targetSource;
}
else {
if (this.beanFactory == null) {
throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
"- cannot resolve target with name '" + this.targetName + "'");
}
if (logger.isDebugEnabled()) {
logger.debug("Refreshing target with name '" + this.targetName + "'");
}
Object target = this.beanFactory.getBean(this.targetName);
return (target instanceof TargetSource ? (TargetSource) target : new SingletonTargetSource(target));
}
}
/**
* Advisor or Advice Advisor
*/
private Advisor namedBeanToAdvisor(Object next) {
try {
return this.advisorAdapterRegistry.wrap(next);
}
catch (UnknownAdviceTypeException ex) {
throw new AopConfigException("Unknown advisor type " + next.getClass() +
"; Can only include Advisor or Advice type beans in interceptorNames chain except for last entry," +
"which may also be target or TargetSource", ex);
}
}
@Override
protected void adviceChanged() {
super.adviceChanged();
if (this.singleton) {
logger.debug("Advice has changed; recaching singleton instance");
synchronized (this) {
this.singletonInstance = null;
}
}
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
// Rely on default serialization; just initialize state after deserialization.
ois.defaultReadObject();
// Initialize transient fields.
this.proxyClassLoader = ClassUtils.getDefaultClassLoader();
}
/**
* Used in the interceptor chain where we need to replace a bean with a prototype
* on creating a proxy.
*/
private static class PrototypePlaceholderAdvisor implements Advisor, Serializable {
private final String beanName;
private final String message;
public PrototypePlaceholderAdvisor(String beanName) {
this.beanName = beanName;
this.message = "Placeholder for prototype Advisor/Advice with bean name '" + beanName + "'";
}
public String getBeanName() {
return beanName;
}
public Advice getAdvice() {
throw new UnsupportedOperationException("Cannot invoke methods: " + this.message);
}
public boolean isPerInstance() {
throw new UnsupportedOperationException("Cannot invoke methods: " + this.message);
}
@Override
public String toString() {
return this.message;
}
}
}