<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="sysProps" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="java.lang.System"/>
<property name="targetMethod" value="getProperties"/>
bean>
<bean id="javaVersion" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="sysProps"/>
<property name="targetMethod" value="getProperty"/>
<property name="arguments" value="java.version"/>
bean>
beans>
下面是System中的静态方法的返回值Properties包含配置的属性的文件的信息,相当于调用静态方法
然后在调用生成的Properties这个Bean的实例的方法的某个属性
public static Properties getProperties() {
SecurityManager sm = getSecurityManager();
if (sm != null) {
sm.checkPropertiesAccess();
}
return props;
}
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
import java.util.Properties;
/**
* descrption:
* authohr: wangji
* date: 2017-08-24 13:35
*/
@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={
"classpath:spring-methodInvoking.xml"})
public class MethodTest extends AbstractJUnit4SpringContextTests{
@Resource(name = "sysProps")
public Properties properties;
@Resource(name ="javaVersion")
public String javaVersion;
@Test
public void test(){
log.info(properties.toString());
log.info(javaVersion.toString());
}
}
//2017-08-24 14:03:26,142 INFO [MethodTest.java:31] : {java.runtime.name=Java(TM) SE Runtime Environment,
// sun.boot.library.path=D:\Program Files\Java\jdk1.8.0_101\jre\bin, java.vm.version=25.101-b13,
//........
// java.library.path=D:\Program Files\Java\jdk1.8.0_101\bin;
// C:\Windows\Sun\Java\bin;C:\Windows\system32;
// C:\Windows;D:\Program Files\Java\jdk1.8.0_101\bin;
//2017-08-24 14:03:26,145 INFO [MethodTest.java:32] : 1.8.0_101
测试结果如同我们想象的一样,可以将某个方法或者某个具体的类的静态方法进行调用
因为我们总会调用这个方法,相当于初始化方法呗,对于返回值,你可以随便返回一个Boolean 这个就将这个Boolean的值注入到了
spring的容器中去了,不过这个不是最好的手段,你可以继承InitializingBean,或者使用注解@PostConstruct,在初始化Bean之前调用这个方法
但是有些时候不想初始化某个Bean你还是可以这么干的。
可以的,其实就是调用刚刚那个类的父类MethodInvokingBean,调用某个静态的方法,调用某个类的实例的方法都可以
最后将MethodInvokingBean注入为Bean其实原理是差不多的。
id="testBean" class="org.springframework.beans.factory.config.MethodInvokingBean">
<property name="staticMethod" value="com.common.utils.test.MethodInvokingBeanTest.test">property>
package com.common.utils.test;
import lombok.extern.slf4j.Slf4j;
/**
* descrption:测试调用静态方法不注入Bean
* authohr: wangji
* date: 2017-08-24 14:20
*/
@Slf4j
public class MethodInvokingBeanTest {
public static void test(){
log.info("调用了这个方法");
}
}
@Resource(name = "testBean")
public MethodInvokingBean methodInvokingBean;
@Test
public void testMethod(){
log.info(methodInvokingBean.getTargetMethod());
}
// 2017-08-24 14:25:52,229 INFO [MethodInvokingBeanTest.java:15] : 调用了这个方法
// 2017-08-24 14:25:52,243 INFO [MethodTest.java:34] : test
@Override
public void afterPropertiesSet() throws Exception {
prepare();
invokeWithTargetException();
}
private Class> targetClass;//目标Class
private Object targetObject;//目标Object
private String targetMethod;//实例的方法
private String staticMethod;//静态的方法
private Object[] arguments = new Object[0];
/** The method we will call */
private Method methodObject; //需要调用的方法
public void prepare() throws ClassNotFoundException, NoSuchMethodException {
if (this.staticMethod != null) {
int lastDotIndex = this.staticMethod.lastIndexOf('.');
if (lastDotIndex == -1 || lastDotIndex == this.staticMethod.length()) {
throw new IllegalArgumentException(“必须使用全限定名")
}
String className = this.staticMethod.substring(0, lastDotIndex);
String methodName = this.staticMethod.substring(lastDotIndex + 1);
this.targetClass = resolveClassName(className);//反射找到类型
this.targetMethod = methodName;//要调用的方法的名称
}
Class> targetClass = getTargetClass();
String targetMethod = getTargetMethod();
if (targetClass == null) {
throw new IllegalArgumentException("Either 'targetClass' or 'targetObject' is required");
}
if (targetMethod == null) {
throw new IllegalArgumentException("Property 'targetMethod' is required");
}
Object[] arguments = getArguments();
Class>[] argTypes = new Class>[arguments.length];//根据传递的参数找到,参数的类型
for (int i = 0; i < arguments.length; ++i) {
argTypes[i] = (arguments[i] != null ? arguments[i].getClass() : Object.class);
}
// Try to get the exact method first.
try {
this.methodObject = targetClass.getMethod(targetMethod, argTypes);
}
catch (NoSuchMethodException ex) {
// Just rethrow exception if we can't get any match.
this.methodObject = findMatchingMethod();//可能位置不对,没有找到方法
if (this.methodObject == null) {
throw ex;
}
}
}
public Object invoke() throws InvocationTargetException, IllegalAccessException {
// In the static case, target will simply be {@code null}.
Object targetObject = getTargetObject();
Method preparedMethod = getPreparedMethod();
if (targetObject == null && !Modifier.isStatic(preparedMethod.getModifiers())) {
throw new IllegalArgumentException("not be non-static without a target");
}
ReflectionUtils.makeAccessible(preparedMethod);
return preparedMethod.invoke(targetObject, getArguments());
}
/**
* Make the given method accessible, explicitly setting it accessible if
* necessary. The {@code setAccessible(true)} method is only called
* when actually necessary, to avoid unnecessary conflicts with a JVM
* SecurityManager (if active).
* @param method the method to make accessible
* @see java.lang.reflect.Method#setAccessible
*/
public static void makeAccessible(Method method) {
if ((!Modifier.isPublic(method.getModifiers()) ||
!Modifier.isPublic(method.getDeclaringClass().getModifiers()))
&& !method.isAccessible()) {
method.setAccessible(true);
}
}
public interface FactoryBean<T> {
/**
* Return an instance (possibly shared or independent) of the object
* managed by this factory.
* As with a {@link BeanFactory}, this allows support for both the
* Singleton and Prototype design pattern.
*
If this FactoryBean is not fully initialized yet at the time of
* the call (for example because it is involved in a circular reference),
* throw a corresponding {@link FactoryBeanNotInitializedException}.
*
As of Spring 2.0, FactoryBeans are allowed to return {@code null}
* objects. The factory will consider this as normal value to be used; it
* will not throw a FactoryBeanNotInitializedException in this case anymore.
* FactoryBean implementations are encouraged to throw
* FactoryBeanNotInitializedException themselves now, as appropriate.
* @return an instance of the bean (can be {@code null})
* @throws Exception in case of creation errors
* @see FactoryBeanNotInitializedException
*/
T getObject() throws Exception;
Class> getObjectType();
boolean isSingleton();
}
private boolean singleton = true;
private boolean initialized = false;
/** Method call result in the singleton case */
private Object singletonObject;
public void afterPropertiesSet() throws Exception {
prepare();//MethodInvoker准备函数
if (this.singleton) {
this.initialized = true;
this.singletonObject = invokeWithTargetException();//函数调用方法的返回值保存下来
}
}
public class MethodInvokingFactoryBean extends MethodInvokingBean implements FactoryBean<Object> {
private boolean singleton = true;
private boolean initialized = false;
private Object singletonObject;
public void setSingleton(boolean singleton) {
this.singleton = singleton;
}
@Override
public void afterPropertiesSet() throws Exception {
prepare();
if (this.singleton) {
this.initialized = true;
this.singletonObject = invokeWithTargetException();
}
}
/**
* Returns the same value each time if the singleton property is set
* to "true", otherwise returns the value returned from invoking the
* specified method on the fly.
*/
@Override
public Object getObject() throws Exception {
//获取那个返回值,也就是当前由于继承了FactoryBean接口,获取到的Bean将是反射方法的返回的结果
if (this.singleton) {
if (!this.initialized) {
throw new FactoryBeanNotInitializedException();
}
// Singleton: return shared object.
return this.singletonObject;
}
else {
// Prototype: new object on each call.
return invokeWithTargetException();
}
}
/**
* Return the type of object that this FactoryBean creates,
* or {@code null} if not known in advance.
*/
@Override
public Class> getObjectType() {//Bean实例的类型,就是反射调用返回值的类型
if (!isPrepared()) {
// Not fully initialized yet -> return null to indicate "not known yet".
return null;
}
return getPreparedMethod().getReturnType();
}
@Override
public boolean isSingleton() {
return this.singleton;
}
}
参考:http://blog.csdn.net/u013185616/article/details/52335864/ FactoryBean的实现原理与作用
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
doGetBean中会调用bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
//如果是对FactoryBean的解引用(&继承FactoryBean,找真实的FactoryBean),
//但bean对象不是FactoryBean,抛出异常
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
//如果Bean实例不是FactoryBean,或者指定名称是FactoryBean的解引用,
//也就是普通的bean调用,则直接返回当前的Bean实例
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
//处理对FactoryBean的调用
Object object = null;
if (mbd == null) {
//从FactoryBean缓存中获取给定名称的实例对象
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean factory = (FactoryBean) beanInstance;
//如果从FacroryBean生产的Bean是单态模式的,则缓存
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
//调用FactoryBeanRegistrySupport(FactoryBean缓存仓库支持类)
//的getObjectFromFactoryBean方法,实现FactoryBean生产Bean对象实例的过程
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
Object object = this.factoryBeanObjectCache.get(beanName);//缓存仓库中存在?
object = doGetObjectFromFactoryBean(factory, beanName);//不存在价值从FactoryBean的实例中加载
protected Object getObjectFromFactoryBean(FactoryBean> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName);
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (object != null && shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
//...
}
}
this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
}
}
return (object != NULL_OBJECT ? object : null);
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (object != null && shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
//.....
}
}
return object;
}
}
private Object doGetObjectFromFactoryBean(final FactoryBean> factory, final String beanName)
throws BeanCreationException {
//......
object = factory.getObject();
return object;
}
今天对于FactoryBean的原理进行了了解,也对于MethodInvokingFactoryBean的使用进行了了解,可以非常方便的将某个方法的返回值弄成Bean的实例
多看看,多总结,提升就在不经意之间, 或许还有很多不懂的地方,请多多指教,毕竟Spring的代码太大,我们只能慢慢的看,慢慢的了解。
类似这样MethodInvokingFactoryBean实例化类比较复杂的使用这个应该还是比较的简单吧!