springboot的服务定位模式

一、文件解析器的例子

在开发中我们可能会解析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的名字一致才行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值