在开发中我们可能会解析CSV,JSON等文件类型,显然要用策略模式
?我们先定义一个Parser接口
public interface Parser {
void parse(String input);
}
Parser接口的实现类有JSONParser,CSVParser
@Component("CSV")
public class CSVParser implements Parser{
@Override
public void parse(String input) {
System.out.println("csv");
}
}
@Component("JSON")
public class JSONParser implements Parser{
@Override
public void parse(String input) {
System.out.println("json");
}
}
然后我们定义一个工厂来获取Parser对象
public interface ParserFactory {
Parser getParser(ContentType type);
}
在该工厂方法的参数是一个枚举
public enum ContentType {
JSON,
XML,
TEXT,
HTML,
IMAGE,
OTHER;
}
?写一个配置类
@Configuration
public class ParserConfig {
@Bean
public FactoryBean serviceLocatorFactoryBean(){
ServiceLocatorFactoryBean factoryBean = new ServiceLocatorFactoryBean();
factoryBean.setServiceLocatorInterface(ParserFactory.class);
return factoryBean;
}
}
测试
@Autowired
private ParserFactory parserFactory;
@Test
void contextLoads() {
Parser parser = parserFactory.getParser(ContentType.JSON);
parser.parse("{'name':'John'}");
}
????????ServiceLocatorFactoryBean实现了接口FactoryBean和InitializingBean,实现InitializingBean会在初始化ServiceLocatorFactoryBean调用afterPropertiesSet方法,具体实现如下代码
@Override
public void afterPropertiesSet() {
if (this.serviceLocatorInterface == null) {
throw new IllegalArgumentException("Property 'serviceLocatorInterface' is required");
}
// Create service locator proxy.
this.proxy = Proxy.newProxyInstance(
this.serviceLocatorInterface.getClassLoader(),
new Class<?>[] {this.serviceLocatorInterface},
new ServiceLocatorInvocationHandler());
}
????????在afterPropertiesSet主要给ServiceLocatorFactoryBean的成员变量proxy赋值,生成代理对象,其中接口就是我们前面的ParserFactory。
? ? ? ? 我们知道实现FactoryBean可以帮助我们创建bean,其中getObject可以获得bean,实现内容如下?
@Override
@Nullable
public Object getObject() {
return this.proxy;
}
?getObject返回的ParserFactory的代理对象,生成动态代理方式是采用JDK代理,主要关注invoke方法,ServiceLocatorFactoryBean的内部类,实现类接口InvocationHandler
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
....
return invokeServiceLocatorMethod(method, args);
}
private Object invokeServiceLocatorMethod(Method method, Object[] args) throws Exception {
Class<?> serviceLocatorMethodReturnType = getServiceLocatorMethodReturnType(method);
try {
String beanName = tryGetBeanName(args);
Assert.state(beanFactory != null, "No BeanFactory available");
if (StringUtils.hasLength(beanName)) {
// Service locator for a specific bean name
return beanFactory.getBean(beanName, serviceLocatorMethodReturnType);
}
else {
// Service locator for a bean type
return beanFactory.getBean(serviceLocatorMethodReturnType);
}
}
catch (BeansException ex) {
if (serviceLocatorExceptionConstructor != null) {
throw createServiceLocatorException(serviceLocatorExceptionConstructor, ex);
}
throw ex;
}
}
?invoke主要先根据方法参数获得beanName,通过beanFactory获得bean实例,因此,要特别注意,传入工厂方法的参数要与被spring管理的bean的名字一致才行