BenDefinitionRegistryPostProcessorとダイナミックエージェントの配合使用例
28402 ワード
このような機能を実現します.注釈をカスタマイズしました.
どのように実現しますか
Spring起動後に
プロキシ類のbeanDefinationを容器に登録し、委託類の容器にあるnameと関連させて容器に注入するのがプロキシ類です.
ここでは、私たちのエージェントの機能は同じです.委託クラスの情報を取得して、要求を遠端に送信して結果を得るので、
このように、私達のプロジェクトのすべての表示されているクラスは、Spring容器の中のBeanDefinationは実質的にFactoryBeanであり、SpringはBenのインスタンスを取得する時にFactoryBenであると発見されたら、そのgetObjectを呼び出します.私達はこの方法の中でタイプによってこの表示類の代理種類のオブジェクトを作成して、getObjectが返したのもそれです.具体的なコードは下記の通り実現されます.
2,私たちはSpringBootを使っていますが、上記の機能は独立したモジュールとして、プロジェクトに依存しています.容器起動時にトリガする必要があります.どうやってトリガしますか?Spring BootのSpring Factores機構を利用して実現します.
Spring Factoresについて、二つの文章を紹介します.Spring Bootの拡張メカニズムのSpring Factores Everable AutoConfigrationの注釈の仕事原理
機能モジュールのresourceディレクトリの下でMETA-INF/spring.factores
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyReference{
}
注释されたフィールドは私たちが代理したいクラスです.Spring起動時にプロキシクラスをこの注釈で識別されたフィールドに注入したいです.どのように実現しますか
Spring起動後に
@MyReference
に表示されるクラスの交替はどうやって実現しますか?プロキシ類のbeanDefinationを容器に登録し、委託類の容器にあるnameと関連させて容器に注入するのがプロキシ類です.
BeanDefinitionRegistryPostProcessor
を用いて実現される.ここでは、私たちのエージェントの機能は同じです.委託クラスの情報を取得して、要求を遠端に送信して結果を得るので、
FactoryBean
とInitializingBean
を利用して、ProxyFactoryBenというクラスを作成して、それらを実現します.内部は委託クラスのタイプを識別するためにメンバー変数を宣言します.この方法はbeanを初期化するときに呼び出される.各表示類には、ProxyFactoryBeanタイプのbeanDefinationが作成されます.このように、私達のプロジェクトのすべての表示されているクラスは、Spring容器の中のBeanDefinationは実質的にFactoryBeanであり、SpringはBenのインスタンスを取得する時にFactoryBenであると発見されたら、そのgetObjectを呼び出します.私達はこの方法の中でタイプによってこの表示類の代理種類のオブジェクトを作成して、getObjectが返したのもそれです.具体的なコードは下記の通り実現されます.
2,私たちはSpringBootを使っていますが、上記の機能は独立したモジュールとして、プロジェクトに依存しています.容器起動時にトリガする必要があります.どうやってトリガしますか?Spring BootのSpring Factores機構を利用して実現します.
Spring Factoresについて、二つの文章を紹介します.Spring Bootの拡張メカニズムのSpring Factores Everable AutoConfigrationの注釈の仕事原理
機能モジュールのresourceディレクトリの下でMETA-INF/spring.factores
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.miao.client.MyAutoConfiguration
MyAutoConfigration@Configuration
@ConditionalOnMissingBean(ProxyFactoryBeanRegistry.class)
@EnableConfigurationProperties(ClientProperties.class)
public class MyAutoConfiguration{
@Autowired
private ClientProperties properties;
// static? proxyFactoryBeanRegistry client
// static , @Configuration , @Bean
// BeanDefinitionRegistryPostProcessor, static
// https://github.com/ulisesbocchio/jasypt-spring-boot/issues/45
//https://stackoverflow.com/questions/41939494/springboot-cannot-enhance-configuration-bean-definition-beannameplaceholderreg
private static Client client = new Client();
@Bean
public Client client() {
log.info(" Client discovery");
ServiceDiscovery discovery = ......
client.setDiscovery(discovery);
client.init();
return client;
}
/**
* Cannot enhance @Configuration bean definition 'com.miao.rpc.client.RpcClientAutoConfiguration'
* since its singleton instance has been created too early.
* The typical cause is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor return type:
* Consider declaring such methods as 'static'.
*
* @Configuration , @Bean BeanDefinitionRegistryPostProcessor, static
* :
* Having a BeanFactoryPostProcessor in a @Configuration class breaks the default post-processing
* of that @Configuration class.
*/
@Bean
public static ProxyFactoryBeanRegistry proxyFactoryBeanRegistry(){
// property ,
String basePackage = PropertityUtil.getProperty("rpc.serverBasePackage");
return new ProxyFactoryBeanRegistry(basePackage, client);
}
次にBenDefinitionRegistryPostProcessorを利用して、bean初期化前に委託類のbeanDefinitionを代理類のbeanDefinitionに変えます.委託類は@MyReferenceに表示され、それを私達に向けたproxyエージェント類を実現します.それらの呼び出しは実際に私達の代理類に呼び出されます./**
* BeanDefinitionRegistryPostProcessor, BeanFactoryPostProcessor
* BeanFactoryPostProcessor bean bean ( ), 。
* BeanDefinitionRegistryPostProcessor bean
*
* beanDefinition, ,
* @Autowired
*/
@Slf4j
public class ProxyFactoryBeanRegistry implements BeanDefinitionRegistryPostProcessor {
private String basePackage;
private Client client;
public ProxyFactoryBeanRegistry(String basePackage, Client client) {
this.basePackage = basePackage;
this.client = client;
}
/**
* , class , class @RpcReference ,
* RpcProxyFactoryBean beanDefinition, beanName ,
* RpcProxyFactoryBean FactoryBean, getObject bean,
* RpcProxyFactoryBean InitializingBean, afterPropertiesSet ,
* , @Autowired @RpcReference ,
* , invoke , , , ,
*
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
log.info(" FactoryBean");
//
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter((metadataReader, metadataReaderFactory) -> true); // ,
Set<BeanDefinition> beanDefinitionSet = scanner.findCandidateComponents(basePackage); //
for (BeanDefinition beanDefinition : beanDefinitionSet) {
log.info(" {}", beanDefinition.getBeanClassName());
String beanClassName = beanDefinition.getBeanClassName(); // class name
Class<?> beanClass = null;
try {
beanClass = Class.forName(beanClassName); // Class
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Field[] fields = beanClass.getDeclaredFields(); // Class field
for (Field field : fields) {
if (!field.isAccessible()) {
field.setAccessible(true);
}
// @MyReference
MyReference reference = field.getAnnotation(MyReference.class);
Class<?> fieldClass = field.getType(); // , proxy
if (reference != null) {
log.info(" " + fieldClass.getName() + " ");
BeanDefinitionHolder holder = createBeanDefinition(fieldClass);
log.info(" ");
// beanDefination
BeanDefinitionReaderUtils.registerBeanDefinition(holder, beanDefinitionRegistry);
}
}
}
}
/**
* fieldClass BeanDefinition
* @return
*/
private BeanDefinitionHolder createBeanDefinition(Class<?> fieldClass) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ProxyFactoryBean.class);
String className = fieldClass.getName();
// bean name ,spring
String beanName = StringUtils.uncapitalize(className.substring(className.lastIndexOf('.')+1));
// ProxyFactoryBean
builder.addPropertyValue("interfaceClass", fieldClass);
builder.addPropertyValue("client", client);
return new BeanDefinitionHolder(builder.getBeanDefinition(), beanName);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
}
ここではプロキシ類に対する要求は同じで、委託類の類名を取得し、要求方法名、要求パラメータ情報などを遠端に送りますので、ここではFactoryBeanを利用して統一したプロキシ類に戻ります./**
* InitializingBean: afterPropertiesSet , interfaceClass
* ProxyFactoryBeanRegistry#createBeanDefinition
* BeanDefination, interfaceClass,client
*/
@Slf4j
public class ProxyFactoryBean implements FactoryBean<Object>, InitializingBean {
private Client client;
private Class<?> interfaceClass; //
private Object proxy;
@Override
public Object getObject() throws Exception {
return proxy;
}
@Override
public Class<?> getObjectType() {
return interfaceClass;
}
@Override
public boolean isSingleton() {
return true; //
}
@Override
public void afterPropertiesSet() throws Exception {
this.proxy = Proxy.newProxyInstance(
interfaceClass.getClassLoader(),
new Class<?>[]{interfaceClass},
(proxy, method, args) -> {
......
});
}
// setxxx
public void setClient(RpcClient client) {
this.client = client;
}
public void setInterfaceClass(Class<?> interfaceClass) {
this.interfaceClass = interfaceClass;
}
}
次はプロジェクトコードの中に次のように直接注ぎ込むだけでいいです. @Autowired
@MyReference
HelloService helloService;
helloService皰xxxメソッドの呼び出しは直接代理クラスをトリガします.