做网站的基本功能,wordpress企业版主体,wordpress 主题教程,怎么在网上做广告宣传作者 | 阿Q来源 | 阿Q说代码一提到Spring#xff0c;大家最先想到的是啥#xff1f;是AOP和IOC的两大特性#xff1f;是Spring中Bean的初始化流程#xff1f;还是基于Spring的Spring Cloud全家桶呢#xff1f;今天我们就从Spring的IOC特性入手#xff0c;聊一聊Spring中把… 作者 | 阿Q来源 | 阿Q说代码一提到Spring大家最先想到的是啥是AOP和IOC的两大特性是Spring中Bean的初始化流程还是基于Spring的Spring Cloud全家桶呢今天我们就从Spring的IOC特性入手聊一聊Spring中把Bean注入Spring容器的几种方式。我们先来简单了解下IOC的概念IOC即控制反转也称为依赖注入是指将对象的创建或者依赖关系的引用从具体的对象控制转为框架或者IOC容器来完成也就是依赖对象的获得被反转了。“可以简单理解为原来由我们来创建对象现在由Spring来创建并控制对象。”xml 方式依稀记得最早接触Spring的时候用的还是SSH框架不知道大家对这个还有印象吗所有的bean的注入得依靠xml文件来完成。它的注入方式分为set方法注入、构造方法注入、字段注入而注入类型分为值类型注入8种基本数据类型和引用类型注入将依赖对象注入。以下是set方法注入的简单样例bean nameteacher classorg.springframework.demo.model.Teacherproperty namename value阿Q/property
/bean对应的实体类代码public class Teacher {private String name;public void setName(String name) {this.name name;}
}xml方式存在的缺点如下xml文件配置起来比较麻烦既要维护代码又要维护配置文件开发效率低项目中配置文件过多维护起来比较困难程序编译期间无法对配置项的正确性进行验证只能在运行期发现并且出错之后不易排查解析xml时无论是将xml一次性装进内存还是一行一行解析都会占用内存资源影响性能。注解方式随着Spring的发展Spring 2.5开始出现了一系列注解除了我们经常使用的Controller、Service、Repository、Component 之外还有一些比较常用的方式接下来我们简单了解下。Configuration Bean当我们需要引入第三方的jar包时可以用Bean注解来标注同时需要搭配Configuration来使用。Configuration用来声明一个配置类可以理解为xml的beans标签Bean 用来声明一个bean将其加入到Spring容器中可以理解为xml的bean标签简单样例将 RedisTemplate 注入 SpringConfiguration
public class RedisConfig {Beanpublic RedisTemplateString, Object redisTemplate(LettuceConnectionFactory redisConnectionFactory) {RedisTemplateString, Object redisTemplate new RedisTemplateString, Object();......return redisTemplate;}
}Import我们在翻看Spring源码的过程中经常会看到Import注解它也可以用来将第三方jar包注入Spring但是它只可以作用在类上。例如在注解EnableSpringConfigured上就包含了Import注解用于将SpringConfiguredConfiguration配置文件加载进Spring容器。Import(SpringConfiguredConfiguration.class)
public interface EnableSpringConfigured {}Import的value值是一个数组一个一个注入比较繁琐因此我们可以搭配ImportSelector接口来使用用法如下Configuration
Import(MyImportSelector.class)
public class MyConfig {}public class MyImportSelector implements ImportSelector {Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {return new String[]{org.springframework.demo.model.Teacher,org.springframework.demo.model.Student};}
}其中selectImports方法返回的数组就会通过Import注解注入到Spring容器中。无独有偶ImportBeanDefinitionRegistrar接口也为我们提供了注入bean的方法。Import(AspectJAutoProxyRegistrar.class)
public interface EnableAspectJAutoProxy {......
}我们点击AspectJAutoProxyRegistrar类发现它实现了ImportBeanDefinitionRegistrar接口它的registerBeanDefinitions方法便是注入bean的过程可以参考下。如果觉得源代码比较难懂可以看一下我们自定义的类Configuration
Import(value {MyImportBeanDefinitionRegistrar.class})
public class MyConfig {}public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry) {RootBeanDefinition tDefinition new RootBeanDefinition(Teacher.class);// 注册 Bean并指定bean的名称和类型registry.registerBeanDefinition(teacher, tDefinition);}}
}这样我们就把Teacher类注入到Spring容器中了。FactoryBean提到FactoryBean就不得不与BeanFactory比较一番。BeanFactory : 是 Factory IOC容器或者对象工厂所有的Bean都由它进行管理FactoryBean : 是Bean 是一个能产生或者修饰对象生成的工厂 Bean实现与工厂模式和修饰器模式类似那么FactoryBean是如何实现bean注入的呢先定义实现了FactoryBean接口的类public class TeacherFactoryBean implements FactoryBeanTeacher {/*** 返回此工厂管理的对象实例**/Overridepublic Teacher getObject() throws Exception {return new Teacher();}/*** 返回此 FactoryBean 创建的对象的类型**/Overridepublic Class? getObjectType() {return Teacher.class;}}然后通过 Configuration Bean的方式将TeacherFactoryBean加入到容器中Configuration
public class MyConfig {Beanpublic TeacherFactoryBean teacherFactoryBean(){return new TeacherFactoryBean();}
}注意我们没有向容器中注入Teacher, 而是直接注入的TeacherFactoryBean然后从容器中拿Teacher这个类型的bean成功运行。BDRegistryPostProcessor看到这个接口不知道对于翻看过Spring源码的你来说熟不熟悉。如果不熟悉的话请往下看要是熟悉的话就再看一遍吧。源码public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {// 注册bean到spring容器中void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}FunctionalInterface
public interface BeanFactoryPostProcessor {void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}BeanFactoryPostProcessor接口是BeanFactory的后置处理器方法postProcessBeanFactory对bean的定义进行控制。今天我们重点来看看postProcessBeanDefinitionRegistry方法它的参数是BeanDefinitionRegistry顾名思义就是与BeanDefinition注册相关的。通过观察该类我们发现它里边包含了registerBeanDefinition方法这个不就是我们想要的吗为了能更好的使用该接口来达到注入bean的目的我们先来看看Spring是如何操作此接口的。看下invokeBeanFactoryPostProcessors方法会发现没有实现PriorityOrdered和Ordered的bean这种跟我们自定义的实现类有关会执行以下代码。while (reiterate) {......invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);......
}进入该方法private static void invokeBeanDefinitionRegistryPostProcessors(Collection? extends BeanDefinitionRegistryPostProcessor postProcessors, BeanDefinitionRegistry registry) {for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {postProcessor.postProcessBeanDefinitionRegistry(registry);}
}会发现实现了BeanDefinitionRegistryPostProcessor接口的bean其postProcessBeanDefinitionRegistry方法会被调用也就是说如果我们自定义接口实现该接口它的postProcessBeanDefinitionRegistry方法也会被执行。实战话不多说直接上代码。自定义接口实现类public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {/*** 初始化过程中先执行**/Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {RootBeanDefinition rootBeanDefinition new RootBeanDefinition(Teacher.class);//Teacher 的定义注册到spring容器中registry.registerBeanDefinition(teacher, rootBeanDefinition);}/*** 初始化过程中后执行**/Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
}启动类代码public static void main(String[] args) {AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext();MyBeanDefinitionRegistryPostProcessor postProcessor new MyBeanDefinitionRegistryPostProcessor();//将自定义实现类加入 Spring 容器context.addBeanFactoryPostProcessor(postProcessor);context.refresh();Teacher bean context.getBean(Teacher.class);System.out.println(bean);
}启动并打印结果org.springframework.demo.model.Teacher2473d930发现已经注入到Spring容器中了。以上就是我们总结的几种将bean注入Spring容器的方式赶快行动起来实战演练一下吧往期推荐换个姿势看 hooks灵感来源组合和 HOC 模式下逻辑视图分离新创意Docker从入门到实战过程全记录没有操作系统程序可以运行起来吗如何在 Kubernetes Pod 内进行网络抓包点分享点收藏点点赞点在看