使用说明
1.定义测试接口
/**
* @author :aoyeye
* @date :Created in 2019/4/29 10:52
* @description:
* @modified By:
*/
public interface TestBeanFactory {
String getBeanName();
}
2.编写实现类
package com.example.demo.service.impl;
import com.example.demo.service.TestBeanFactory;
import org.springframework.stereotype.Service;
/**
* @author :aoyeye
* @date :Created in 2019/4/29 10:58
* @description:
* @modified By:
*/
@Service("A")
public class TestBeanFactoryImplA implements TestBeanFactory {
@Override
public String getBeanName() {
return TestBeanFactoryImplA.class.getName();
}
}
package com.example.demo.service.impl;
import com.example.demo.service.TestBeanFactory;
import org.springframework.stereotype.Service;
/**
* @author :aoyeye
* @date :Created in 2019/4/29 10:59
* @description:
* @modified By:
*/
@Service("B")
public class TestBeanFactoryImplB implements TestBeanFactory {
@Override
public String getBeanName() {
return TestBeanFactoryImplB.class.getName();
}
}
3.定义代理接口
package com.example.demo.service;
/**
* 代理接口
* @author :aoyeye
* @date :Created in 2019/4/29 11:03
* @description:
* @modified By:
*/
public interface BeanFactory {
TestBeanFactory get(String type);
}
4.配置注入到ServiceLocatorFactoryBean
package com.example.demo.config;
import com.example.demo.service.BeanFactory;
import org.springframework.beans.factory.config.ServiceLocatorFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author :aoyeye
* @date :Created in 2019/4/29 10:53
* @description:
* @modified By:
*/
@Configuration
public class BeanFactoryConfig {
@Bean
public ServiceLocatorFactoryBean dataWarehouseFactory() {
ServiceLocatorFactoryBean dataWarehouseFactory = new ServiceLocatorFactoryBean();
dataWarehouseFactory.setServiceLocatorInterface(BeanFactory.class);
return dataWarehouseFactory;
}
}
5.测试
@Test
public void testGetBean() {
String A = "A";
TestBeanFactory testBeanFactory = beanFactory.get(A);
String beanName = testBeanFactory.getBeanName();
System.out.println("=============="+beanName);
}
输出:==============com.example.demo.service.impl.TestBeanFactoryImplA
原理说明
主要思想通过JDK动态代理方式反射查找相关class method
首先查看:ServiceLocatorFactoryBean.afterPropertiesSet方法
/**
* BeanFactory调用的初始化bean接口时调用(InitializingBean)
*/
@Override
public void afterPropertiesSet() {
if (this.serviceLocatorInterface == null) {
throw new IllegalArgumentException("Property 'serviceLocatorInterface' is required");
}
//生成代理
this.proxy = Proxy.newProxyInstance(
this.serviceLocatorInterface.getClassLoader(),
new Class<?>[] {this.serviceLocatorInterface},
new ServiceLocatorInvocationHandler());
}
接下来它是如何查询实现的类呢?查看内部类ServiceLocatorInvocationHandler
private class ServiceLocatorInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//特殊处理Object类的几个方法 hashcode() equal() toString()
if (ReflectionUtils.isEqualsMethod(method)) {
// Only consider equal when proxies are identical.
return (proxy == args[0]);
}
else if (ReflectionUtils.isHashCodeMethod(method)) {
// Use hashCode of service locator proxy.
return System.identityHashCode(proxy);
}
else if (ReflectionUtils.isToStringMethod(method)) {
return "Service locator: " + serviceLocatorInterface;
}
else {
return invokeServiceLocatorMethod(method, args);
}
}
private Object invokeServiceLocatorMethod(Method method, Object[] args) throws Exception {
Class<?> serviceLocatorMethodReturnType = getServiceLocatorMethodReturnType(method);
try {
String beanName = tryGetBeanName(args);
if (StringUtils.hasLength(beanName)) {
// 根据beanName查找
return beanFactory.getBean(beanName, serviceLocatorMethodReturnType);
}
else {
// 根据bean类型查找
return beanFactory.getBean(serviceLocatorMethodReturnType);
}
}
catch (BeansException ex) {
if (serviceLocatorExceptionConstructor != null) {
throw createServiceLocatorException(serviceLocatorExceptionConstructor, ex);
}
throw ex;
}
}
}
如上可知可以通过bean名称和类型两种方式查找bean,demo演示了根据bean name方式查找,那通过bean type如何做呢?
修改
public interface BeanFactory {
TestBeanFactory get(String type);
TestBeanFactory get();
}
测试调用get(),发现:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.example.demo.service.TestBeanFactory' available: expected single matching bean but found 2: A,B
日志可知根据bean type查询到了两个bean,因此系统出错。
总结
1.实际开发过程中如果相同bean类型只有一个,不建议使用ServiceLocatorFactoryBean增加复杂性;
2.如果对于不同输入需要调用不同实现类,而返回类型,数据结构等信息相同时,可以考虑使用ServiceLocatorFactoryBean;例如:数据库连接池时,根据不同数据库类型名称获取数据库信息
网友评论