<small id='nKv0u'></small> <noframes id='13ADcTVU'>

  • <tfoot id='pFo5eQ9D6J'></tfoot>

      <legend id='CliBAj1q'><style id='HBpb'><dir id='homH'><q id='2necUoVM9B'></q></dir></style></legend>
      <i id='DkyifpdOlS'><tr id='UiwbJA0TP'><dt id='tXEOh1k'><q id='jNZLMW5'><span id='Le07HwEJ'><b id='cEs54B9YK'><form id='Y1lwKmh'><ins id='8S1mqfL'></ins><ul id='MnIrhCN'></ul><sub id='9Lku'></sub></form><legend id='b1EATrYo'></legend><bdo id='AhHWKefrT'><pre id='bmeIBNXOk3'><center id='Z1vUIOQH'></center></pre></bdo></b><th id='U9fCl'></th></span></q></dt></tr></i><div id='3Mjt5es'><tfoot id='My9UWEe'></tfoot><dl id='it1Kx'><fieldset id='RCr1ns'></fieldset></dl></div>

          <bdo id='hkBdeN'></bdo><ul id='ThSv'></ul>

          1. <li id='XtZEc'></li>
            登陆

            一号站平台登录地址-携程大佬带你写一个可扩展的Spring插件

            admin 2019-09-07 223人围观 ,发现0个评论

            # 布景介绍

            Spring现在简直现已成为了Java开发的必备结构,在享用Spring结构本身强壮才能的一起,有时咱们也会期望自己研制的组件和Spring进行整合,然后使得组件更易于上手,而且协作Spring运用能发挥更强壮的效果。

            Apollo装备中心的Java客户端在前一段时刻也供给了和Spring整合的功用,Apollo既支撑传统的依据XML的装备,也支撑现在比较盛行的依据Java的装备。下面就以Apollo为例,简略介绍一下扩展Spring的几种办法。

            # 依据XML装备的扩展


            信任从事Java开发有一些年初的人必定会对Spring的xml装备办法十分了解。不管是bean的界说,仍是Spring本身的装备,前期都是经过xml装备完结的。信任仍是有一大批留传项目现在仍是依据xml装备的,所以支撑xml的一号站平台登录地址-携程大佬带你写一个可扩展的Spring插件装备办法是一个必选项。

            1、界说schema

            要支撑XML的装备办法,首要需求界说一套XML Schema来描绘组件所供给的功用。

            Apollo供给了向Spring Property Sources注入装备的功用,所以schema中就需求描绘咱们期望用户供给的namespace以及namespace之间的排序等元数据。

            下面便是Apollo的schema示例,能够看到xml的装备节点姓名是config,而且有两个可选特点:namespaces和order,类型分别是string和int。



            xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            targetNamespace="http://www.ctrip.com/schema/apollo"
            elementFormDefault="qualified"
            attributeFormDefault="un一号站平台登录地址-携程大佬带你写一个可扩展的Spring插件qualified">













            The comma-separated list of namespace names to integrate with Spring property sources.
            If not specified, then default to application namespace.
            ]]>






            The order of the config, default to Ordered.LOWEST_PRECEDENCE, which is Integer.MAX_VALUE.
            If there are properties with the same name in different apollo configs, the config with smaller order wins.
            ]]>







            2、创立NamespaceHandler

            除了XML Schema,咱们还需求创立一个自界说的NamespaceHandler来担任解析用户在XML中的装备。

            承继NamespaceHandlerSupport

            为了简化代码,咱们一般会承继一个helper类:NamespaceHandlerSupport,然后在init办法中注册处理咱们自界说节点的BeanDefinitionParser。

            下面的示例告知Spring由咱们自界说的的BeanParser来处理xml中的config节点信息。

            public class NamespaceHandler extends NamespaceHandlerSupport {
            @Override
            public void init() {
            registerBeanDefinitionParser("config", new BeanParser());
            }
            }

            自界说BeanDefinitionParser

            自界说的BeanDefinitionParser担任解析xml中的config节点信息,记载用户的装备信息,为后边和Spring整合做好衬托。

            Apollo的自界说BeanDefinitionParser首要做了两件作业:

            • 记载用户装备的namespace和order
            • 向Spring注册Bean:ConfigPropertySourcesProcessor,这个bean后边会实践处理用户装备的namespace和order,然后完结装备注入到Spring中的功用
            public class BeanParser extends AbstractSingleBeanDefinitionParser {
            @Override
            protected Class
            return ConfigPropertySourcesProcessor.class;
            }
            @Override
            protected boolean shouldGenerateId() {
            return true;
            }
            @Override
            protected void doParse(Elem一号站平台登录地址-携程大佬带你写一个可扩展的Spring插件ent element, BeanDefinitionBuilder builder) {
            String namespaces = element.getAttribute("namespaces");
            //default to application
            if (Strings.isNullOrEmpty(namespaces)) {
            namespaces = ConfigConsts.一号站平台登录地址-携程大佬带你写一个可扩展的Spring插件NAMESPACE_APPLICATION;
            }
            int order = Ordered.LOWEST_PRECEDENCE;
            String orderAttribute = element.getAttribute("order");
            if (!Strings.isNullOrEmpty(orderAttribute)) {
            try {
            order = Integer.parseInt(orderAttribute);
            } catch (Throwable ex) {
            throw new IllegalArgumentException(
            String.format("Invalid order: %s for namespaces: %s", orderAttribute, namespaces));
            }
            }
            PropertySourcesProcessor.addNamespaces(NAMESPACE_SPLITTER.splitToList(namespaces), order);
            }
            }

            3、注册Spring handler和Spring schema

            依据XML装备扩展Spring的主体代码根本便是上面这些,剩余的便是要让Spring解析xml装备文件的过程中辨认咱们的自界说节点,而且转交到咱们的NamespaceHandler处理。

            META-INF/spring.handlers

            首要需求在META-INF目录下创立一个spring.handlers文件,来装备咱们自界说的XML Schema Namespace到咱们自界说的NamespaceHandler映射联系。

            http\://www.ctrip.com/schema/apollo=com.ctrip.framework.apollo.spring.config.NamespaceHandler

            META-INF/spring.schemas

            咱们还需求在META-INF目录下创立一个spring.schemas,来装备咱们自界说的XML Schema地址到实践Jar包中的classpath映射联系(防止Spring真的去服务器上下载不存在的文件)。

            为了简略起见,Apollo把实践的schema文件放在了META-INF目录下。

            http\://www.ctrip.com/schema/apollo-1.0.0.xsd=/META-INF/apollo-1.0.0.xsd
            http\://www.ctrip.com/schema/apollo.xsd=/META-INF/apollo-1.0.0.xsd

            4、样例目录结构

            依照上面的办法,终究Apollo和Spring整合的相关代码结构如下图所示:

            5、运用样例

            依据XML装备的运用样例如下:



            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:apollo="http://www.ctrip.com/schema/apollo"
            xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.ctrip.com/schema/apollo http://www.ctrip.com/schema/apollo.xsd">




            # 依据Java装备的扩展

            从Spring 3.0开端,一种新的依据Java的装备办法呈现了。

            经过这种办法,咱们在开发Spring项目的过程中再也不需求去装备繁琐的xml文件了,只需求在Configuration类中装备就能够了,大大的简化了Spring的运用。

            别的,这也是Spring Boot默许的装备办法,所以主张也支撑这一特性。

            1、@Import注解

            支撑Java装备扩展的要害点便是@Import注解,Spring 3.0供给了这个注解用来支撑在Configuration类中引进其它的装备类,包括Configuration类, ImportSelector和ImportBeanDefinitionRegistrar的完结类。

            咱们能够经过这个注解来引进自界说的扩展Bean。

            2、自界说注解

            和依据XML装备相似的,咱们需求供给给用户一个注解来装备需求注入到Spring Property Sources的namespaces和order。

            下面便是Apollo供给的@EnableApolloConfig注解,答应用户传入namespaces和order信息。

            @Retention(RetentionPolicy.RUNTIME)
            @Target(ElementType.TYPE)
            @Documented
            @Import(ApolloConfigRegistrar.class)
            public @interface EnableApolloConfig {
            /**
            * Apollo namespaces to inject configuration into Spring Property Sources.
            */
            String[] value() default {ConfigConsts.NAMESPACE_APPLICATION};
            /**
            * The ord一号站平台登录地址-携程大佬带你写一个可扩展的Spring插件er of the apollo config, default is {@link Ordered#LOWEST_PRECEDENCE}, which is Integer.MAX_VALUE.
            * If there are properties with the same name in different apollo configs, the apollo config with smaller order wins.
            */
            int order() default Ordered.LOWEST_PRECEDENCE;
            }

            这儿的要害点是在注解上运用了@Import(ApolloConfigRegistrar.class),然后Spring在处理@EnableApolloConfig时会实例化并调用ApolloConfigRegistrar的办法。

            3、自界说ImportBeanDefinitionRegistrar完结

            ImportBeanDefinitionRegistrar接口界说了registerBeanDefinitions办法,然后答应咱们向Spring注册必要的Bean。

            Apollo的自界说ImportBeanDefinitionRegistrar完结(ApolloConfigRegistrar)首要做了两件作业:

            • 记载用户装备的namespace和order
            • 向Spring注册一号站平台登录地址-携程大佬带你写一个可扩展的Spring插件Bean:PropertySourcesProcessor,这个bean后边会实践处理用户装备的namespace和order,然后完结装备注入到Spring中的功用
            public class ApolloConfigRegistrar implements ImportBeanDefinitionRegistrar {
            @Override
            public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata
            .getAnnotationAttributes(EnableApolloConfig.class.getName()));
            String[] namespaces = attributes.getStringArray("value");
            int order = attributes.getNumber("order");
            PropertySourcesProcessor.addNamespaces(Lists.newArrayList(namespaces), order);
            BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesProcessor.class.getName(),
            PropertySourcesProcessor.class);
            }
            }

            4、样例目录结构

            依照上面的办法,终究Apollo和Spring整合的相关代码结构如下图所示:

            5、运用样例

            依据Java装备的运用样例如下:

            @Configuration
            @EnableApolloConfig(value = "application", order = 1)
            public class AppConfig {}

            # Spring容器的扩展点

            前面两节简略介绍了扩展Spring的两种办法:依据XML和依据Java的装备。经过这两种办法,咱们能够在运行时收集到用户的装备信息,一起向Spring注册实践处理这些装备信息的Bean。

            但这些注册进去的Bean实践上是怎么作业的呢?咱们经过什么办法能使咱们的程序逻辑和Spring的容器严密协作,并无缝刺进到用户bean的生命周期中呢?

            这儿简略介绍Spring容器最常用的两个扩展点:BeanFactoryPostProcessor和BeanPostProcessor。

            1、BeanFactoryPostProcessor

            BeanFactoryPostProcessor供给了一个办法:postProcessBeanFactory。

            这个办法会被Spring在容器初始化过程中调用,调用机遇是一切bean的界说信息都现已初始化好,可是这些bean还没有实例化。

            Apollo就运用这个时刻点把装备信息注入到Spring Property Sources中,然后用户的bean在真实实例化时,一切需求的装备信息现已预备好了。

            public class PropertySourcesProcessor implements BeanFactoryPostProcessor {
            private static final AtomicBoolean PROPERTY_SOURCES_INITIALIZED = new AtomicBoolean(false);
            @Override
            public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            if (!PROPERTY_SOURCES_INITIALIZED.compareAndSet(false, true)) {
            //already initialized
            return;
            }
            //initialize and inject Apollo config to Spring Property Sources
            initializePropertySources();
            }
            }

            2、BeanPostProcessor

            BeanPostProcessor供给了两个办法:postProcessBeforeInitialization和postProcessAfterInitialization,首要针对bean初始化供给扩展。

            • postProc我一直在你身边essBeforeInitialization会在每一个bean实例化之后、初始化(如afterPropertiesSet办法)之前被调用。
            • postProcessAfterInitialization则在每一个bean初始化之后被调用。

            咱们常用的@Autowired注解便是经过postProcessBeforeInitialization完结的(AutowiredAnnotationBeanPostProcessor)。

            Apollo供给了@ApolloConfig注解来完结实例化时注入Config目标实例,所以完结逻辑和@Autowired相似。

            public class ApolloAnnotationProcessor implements BeanPostProcessor {
            @Override
            public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            Class clazz = bean.getClass();
            processFields(bean, clazz.getDeclaredFields());
            return bean;
            }
            @Override
            public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            return bean;
            }
            private void processFields(Object bean, Field[] declaredFields) {
            for (Field field : declaredFields) {
            ApolloConfig annotation = AnnotationUtils.getAnnotation(field, ApolloConfig.class);
            if (annotation == null) {
            continue;
            }
            Preconditions.checkArgument(Config.class.isAssignableFrom(field.getType()),
            "Invalid type: %s for field: %s, should be Config", field.getType(), field);
            String namespace = annotation.value();
            Config config = ConfigService.getConfig(namespace);
            ReflectionUtils.makeAccessible(field);
            ReflectionUtils.setField(field, bean, config);
            }
            }
            }

            仔细阅读上面的代码就会发现Apollo在用户bean初始化前会依据@ApolloConfig的装备注入对应namespace的Config实例。

            # 总结

            本文简略介绍了扩展Spring的几种办法,下面简略小结一下,期望对咱们有所协助。

            经过依据XML和依据Java的装备扩展,能够运用户经过Spring运用咱们研制的组件,供给很好的易用性。

            经过Spring容器最常用的两个扩展点:BeanFactoryPostProcessor和BeanPostProcessor,能够使咱们的程序逻辑和Spring容器严密协作,无缝刺进到用户bean的生命周期中,发挥更强壮的效果。


            免费共享Java教程,详细包括前端(web,css,HTML.......)后端(零根底,数据库,ssm以及其他前沿教程)只要你想不到的,没有我没有的。需求的私信

            作者:宋顺 来历:nobodyiam.com
            请关注微信公众号
            微信二维码
            不容错过
            Powered By Z-BlogPHP