Skip to content

Commit cf290ab

Browse files
committed
Extracted simple MethodInvokingBean as alternative to (and base class for) MethodInvokingFactoryBean
Issue: SPR-11196
1 parent a8577da commit cf290ab

File tree

3 files changed

+185
-122
lines changed

3 files changed

+185
-122
lines changed
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*
2+
* Copyright 2002-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.beans.factory.config;
18+
19+
import java.lang.reflect.InvocationTargetException;
20+
21+
import org.springframework.beans.TypeConverter;
22+
import org.springframework.beans.factory.BeanClassLoaderAware;
23+
import org.springframework.beans.factory.BeanFactory;
24+
import org.springframework.beans.factory.BeanFactoryAware;
25+
import org.springframework.beans.factory.InitializingBean;
26+
import org.springframework.beans.support.ArgumentConvertingMethodInvoker;
27+
import org.springframework.util.ClassUtils;
28+
29+
/**
30+
* Simple method invoker bean: just invoking a target method, not expecting a result
31+
* to expose to the container (in contrast to {@link MethodInvokingFactoryBean}).
32+
*
33+
* <p>This invoker supports any kind of target method. A static method may be specified
34+
* by setting the {@link #setTargetMethod targetMethod} property to a String representing
35+
* the static method name, with {@link #setTargetClass targetClass} specifying the Class
36+
* that the static method is defined on. Alternatively, a target instance method may be
37+
* specified, by setting the {@link #setTargetObject targetObject} property as the target
38+
* object, and the {@link #setTargetMethod targetMethod} property as the name of the
39+
* method to call on that target object. Arguments for the method invocation may be
40+
* specified by setting the {@link #setArguments arguments} property.
41+
*
42+
* <p>This class depends on {@link #afterPropertiesSet()} being called once
43+
* all properties have been set, as per the InitializingBean contract.
44+
*
45+
* <p>An example (in an XML based bean factory definition) of a bean definition
46+
* which uses this class to call a static initialization method:
47+
*
48+
* <pre class="code">
49+
* &lt;bean id="myObject" class="org.springframework.beans.factory.config.MethodInvokingBean">
50+
* &lt;property name="staticMethod" value="com.whatever.MyClass.init"/>
51+
* &lt;/bean></pre>
52+
*
53+
* <p>An example of calling an instance method to start some server bean:
54+
*
55+
* <pre class="code">
56+
* &lt;bean id="myStarter" class="org.springframework.beans.factory.config.MethodInvokingBean">
57+
* &lt;property name="targetObject" ref="myServer"/>
58+
* &lt;property name="targetMethod" value="start"/>
59+
* &lt;/bean></pre>
60+
*
61+
* @author Juergen Hoeller
62+
* @since 4.0.3
63+
* @see MethodInvokingFactoryBean
64+
* @see org.springframework.util.MethodInvoker
65+
*/
66+
public class MethodInvokingBean extends ArgumentConvertingMethodInvoker
67+
implements BeanClassLoaderAware, BeanFactoryAware, InitializingBean {
68+
69+
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
70+
71+
private ConfigurableBeanFactory beanFactory;
72+
73+
74+
@Override
75+
public void setBeanClassLoader(ClassLoader classLoader) {
76+
this.beanClassLoader = classLoader;
77+
}
78+
79+
@Override
80+
protected Class<?> resolveClassName(String className) throws ClassNotFoundException {
81+
return ClassUtils.forName(className, this.beanClassLoader);
82+
}
83+
84+
@Override
85+
public void setBeanFactory(BeanFactory beanFactory) {
86+
if (beanFactory instanceof ConfigurableBeanFactory) {
87+
this.beanFactory = (ConfigurableBeanFactory) beanFactory;
88+
}
89+
}
90+
91+
/**
92+
* Obtain the TypeConverter from the BeanFactory that this bean runs in,
93+
* if possible.
94+
* @see ConfigurableBeanFactory#getTypeConverter()
95+
*/
96+
@Override
97+
protected TypeConverter getDefaultTypeConverter() {
98+
if (this.beanFactory != null) {
99+
return this.beanFactory.getTypeConverter();
100+
}
101+
else {
102+
return super.getDefaultTypeConverter();
103+
}
104+
}
105+
106+
107+
@Override
108+
public void afterPropertiesSet() throws Exception {
109+
prepare();
110+
invokeWithTargetException();
111+
}
112+
113+
/**
114+
* Perform the invocation and convert InvocationTargetException
115+
* into the underlying target exception.
116+
*/
117+
protected Object invokeWithTargetException() throws Exception {
118+
try {
119+
return invoke();
120+
}
121+
catch (InvocationTargetException ex) {
122+
if (ex.getTargetException() instanceof Exception) {
123+
throw (Exception) ex.getTargetException();
124+
}
125+
if (ex.getTargetException() instanceof Error) {
126+
throw (Error) ex.getTargetException();
127+
}
128+
throw ex;
129+
}
130+
}
131+
132+
}
Lines changed: 26 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,17 +16,8 @@
1616

1717
package org.springframework.beans.factory.config;
1818

19-
import java.lang.reflect.InvocationTargetException;
20-
21-
import org.springframework.beans.TypeConverter;
22-
import org.springframework.beans.factory.BeanClassLoaderAware;
23-
import org.springframework.beans.factory.BeanFactory;
24-
import org.springframework.beans.factory.BeanFactoryAware;
2519
import org.springframework.beans.factory.FactoryBean;
2620
import org.springframework.beans.factory.FactoryBeanNotInitializedException;
27-
import org.springframework.beans.factory.InitializingBean;
28-
import org.springframework.beans.support.ArgumentConvertingMethodInvoker;
29-
import org.springframework.util.ClassUtils;
3021

3122
/**
3223
* {@link FactoryBean} which returns a value which is the result of a static or instance
@@ -44,10 +35,14 @@
4435
* {@link #setSingleton singleton} property may be set to "false", to cause this
4536
* factory to invoke the target method each time it is asked for an object.
4637
*
47-
* <p>A static target method may be specified by setting the
48-
* {@link #setTargetMethod targetMethod} property to a String representing the static
49-
* method name, with {@link #setTargetClass targetClass} specifying the Class that
50-
* the static method is defined on. Alternatively, a target instance method may be
38+
* <p><b>NOTE: If your target method does not produce a result to expose, consider
39+
* {@link MethodInvokingBean} instead, which avoids the type determination and
40+
* lifecycle limitations that this {@link MethodInvokingFactoryBean} comes with.</b>
41+
*
42+
* <p>This invoker supports any kind of target method. A static method may be specified
43+
* by setting the {@link #setTargetMethod targetMethod} property to a String representing
44+
* the static method name, with {@link #setTargetClass targetClass} specifying the Class
45+
* that the static method is defined on. Alternatively, a target instance method may be
5146
* specified, by setting the {@link #setTargetObject targetObject} property as the target
5247
* object, and the {@link #setTargetMethod targetMethod} property as the name of the
5348
* method to call on that target object. Arguments for the method invocation may be
@@ -61,41 +56,34 @@
6156
*
6257
* <pre class="code">
6358
* &lt;bean id="myObject" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
64-
* &lt;property name="staticMethod">&lt;value>com.whatever.MyClassFactory.getInstance&lt;/value>&lt;/property>
59+
* &lt;property name="staticMethod" value="com.whatever.MyClassFactory.getInstance"/>
6560
* &lt;/bean></pre>
6661
*
6762
* <p>An example of calling a static method then an instance method to get at a
6863
* Java system property. Somewhat verbose, but it works.
6964
*
7065
* <pre class="code">
7166
* &lt;bean id="sysProps" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
72-
* &lt;property name="targetClass">&lt;value>java.lang.System&lt;/value>&lt;/property>
73-
* &lt;property name="targetMethod">&lt;value>getProperties&lt;/value>&lt;/property>
67+
* &lt;property name="targetClass" value="java.lang.System"/>
68+
* &lt;property name="targetMethod" value="getProperties"/>
7469
* &lt;/bean>
7570
*
7671
* &lt;bean id="javaVersion" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
77-
* &lt;property name="targetObject">&lt;ref local="sysProps"/>&lt;/property>
78-
* &lt;property name="targetMethod">&lt;value>getProperty&lt;/value>&lt;/property>
79-
* &lt;property name="arguments">
80-
* &lt;list>
81-
* &lt;value>java.version&lt;/value>
82-
* &lt;/list>
83-
* &lt;/property>
72+
* &lt;property name="targetObject" value="sysProps"/>
73+
* &lt;property name="targetMethod" value="getProperty"/>
74+
* &lt;property name="arguments" value="java.version"/>
8475
* &lt;/bean></pre>
8576
*
8677
* @author Colin Sampaleanu
8778
* @author Juergen Hoeller
8879
* @since 21.11.2003
80+
* @see MethodInvokingBean
81+
* @see org.springframework.util.MethodInvoker
8982
*/
90-
public class MethodInvokingFactoryBean extends ArgumentConvertingMethodInvoker
91-
implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware, InitializingBean {
83+
public class MethodInvokingFactoryBean extends MethodInvokingBean implements FactoryBean<Object> {
9284

9385
private boolean singleton = true;
9486

95-
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
96-
97-
private ConfigurableBeanFactory beanFactory;
98-
9987
private boolean initialized = false;
10088

10189
/** Method call result in the singleton case */
@@ -104,75 +92,18 @@ public class MethodInvokingFactoryBean extends ArgumentConvertingMethodInvoker
10492

10593
/**
10694
* Set if a singleton should be created, or a new object on each
107-
* request else. Default is "true".
95+
* {@link #getObject()} request otherwise. Default is "true".
10896
*/
10997
public void setSingleton(boolean singleton) {
11098
this.singleton = singleton;
11199
}
112100

113-
@Override
114-
public boolean isSingleton() {
115-
return this.singleton;
116-
}
117-
118-
@Override
119-
public void setBeanClassLoader(ClassLoader classLoader) {
120-
this.beanClassLoader = classLoader;
121-
}
122-
123-
@Override
124-
protected Class<?> resolveClassName(String className) throws ClassNotFoundException {
125-
return ClassUtils.forName(className, this.beanClassLoader);
126-
}
127-
128-
@Override
129-
public void setBeanFactory(BeanFactory beanFactory) {
130-
if (beanFactory instanceof ConfigurableBeanFactory) {
131-
this.beanFactory = (ConfigurableBeanFactory) beanFactory;
132-
}
133-
}
134-
135-
/**
136-
* Obtain the TypeConverter from the BeanFactory that this bean runs in,
137-
* if possible.
138-
* @see ConfigurableBeanFactory#getTypeConverter()
139-
*/
140-
@Override
141-
protected TypeConverter getDefaultTypeConverter() {
142-
if (this.beanFactory != null) {
143-
return this.beanFactory.getTypeConverter();
144-
}
145-
else {
146-
return super.getDefaultTypeConverter();
147-
}
148-
}
149-
150-
151101
@Override
152102
public void afterPropertiesSet() throws Exception {
153103
prepare();
154104
if (this.singleton) {
155105
this.initialized = true;
156-
this.singletonObject = doInvoke();
157-
}
158-
}
159-
160-
/**
161-
* Perform the invocation and convert InvocationTargetException
162-
* into the underlying target exception.
163-
*/
164-
private Object doInvoke() throws Exception {
165-
try {
166-
return invoke();
167-
}
168-
catch (InvocationTargetException ex) {
169-
if (ex.getTargetException() instanceof Exception) {
170-
throw (Exception) ex.getTargetException();
171-
}
172-
if (ex.getTargetException() instanceof Error) {
173-
throw (Error) ex.getTargetException();
174-
}
175-
throw ex;
106+
this.singletonObject = invokeWithTargetException();
176107
}
177108
}
178109

@@ -193,7 +124,7 @@ public Object getObject() throws Exception {
193124
}
194125
else {
195126
// Prototype: new object on each call.
196-
return doInvoke();
127+
return invokeWithTargetException();
197128
}
198129
}
199130

@@ -210,4 +141,9 @@ public Class<?> getObjectType() {
210141
return getPreparedMethod().getReturnType();
211142
}
212143

144+
@Override
145+
public boolean isSingleton() {
146+
return this.singleton;
147+
}
148+
213149
}

0 commit comments

Comments
 (0)