SpringIOC随笔(六)-依赖注入(DI)

「爱情、让人受尽委屈。」 2022-12-16 14:25 318阅读 0赞

SpringIOC随笔(六)-依赖注入(DI)

  • DI(Dependency Injection)
  • 概念:对象之间的关系的装配交给容器来管理。
  • 注入的方式:

    1. 构造注入:

      1. 顾名思义,构造注入就是使用构造方法注入,所以使用构造注入肯定要写对应的构造方法。下面直接上例子:

      public class User implements Serializable {
      private static final long serialVersionUID = 84601116866236075L;

      1. private String username;
      2. private String password;
      3. private Department department;
      4. public User() {
      5. }
      6. public User(String username, String password) {
      7. this.username = username;
      8. this.password = password;
      9. }
      10. public User(String username, String password, Department department) {
      11. this.username = username;
      12. this.password = password;
      13. this.department = department;
      14. }
      15. public String getUsername() {
      16. return username;
      17. }
      18. public void setUsername(String username) {
      19. this.username = username;
      20. }
      21. public String getPassword() {
      22. return password;
      23. }
      24. public void setPassword(String password) {
      25. this.password = password;
      26. }
      27. public Department getDepartment() {
      28. return department;
      29. }
      30. public void setDepartment(Department department) {
      31. this.department = department;
      32. }
      33. @Override
      34. public String toString() {
      35. return "User{" +
      36. "username='" + username + '\'' +
      37. ", password='" + password + '\'' +
      38. ", department=" + department +
      39. '}';
      40. }

      }
      public class Department implements Serializable {
      private static final long serialVersionUID = -7390074405145933835L;

      1. private Integer id;
      2. private String departmentName;
      3. private String address;
      4. public Department() {
      5. }
      6. public Department(Integer id, String departmentName, String address) {
      7. this.id = id;
      8. this.departmentName = departmentName;
      9. this.address = address;
      10. }
      11. public Integer getId() {
      12. return id;
      13. }
      14. public void setId(Integer id) {
      15. this.id = id;
      16. }
      17. public String getDepartmentName() {
      18. return departmentName;
      19. }
      20. public void setDepartmentName(String departmentName) {
      21. this.departmentName = departmentName;
      22. }
      23. public String getAddress() {
      24. return address;
      25. }
      26. public void setAddress(String address) {
      27. this.address = address;
      28. }
      29. @Override
      30. public String toString() {
      31. return "Department{" +
      32. "id=" + id +
      33. ", departmentName='" + departmentName + '\'' +
      34. ", address='" + address + '\'' +
      35. '}';
      36. }

      }

      1. 3.
      2. ```xml
      3. <?xml version="1.0" encoding="UTF-8"?>
      4. <beans xmlns="http://www.springframework.org/schema/beans"
      5. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      7. <bean id="user" class="com.fxyh.spring.di.User">
      8. <constructor-arg index="0" value="zhangsan"/>
      9. <constructor-arg index="1" value="123456"/>
      10. <!--ref方式-->
      11. <!--<constructor-arg index="2" ref="department"/>-->
      12. <constructor-arg index="2">
      13. <!--内部bean方式-->
      14. <bean class="com.fxyh.spring.di.Department">
      15. <constructor-arg index="0" value="2"/>
      16. <constructor-arg index="1" value="Ali"/>
      17. <constructor-arg index="2" value="hangzhou"/>
      18. </bean>
      19. </constructor-arg>
      20. </bean>
      21. <bean id="department" class="com.fxyh.spring.di.Department">
      22. <constructor-arg index="0" value="1"/>
      23. <constructor-arg index="1" value="Baidu"/>
      24. <constructor-arg index="2" value="shengzhen"/>
      25. </bean>
      26. </beans>
      1. @ContextConfiguration(“classpath*:applicationContext-di.xml”)
        @RunWith(SpringJUnit4ClassRunner.class)
        public class UserTest {
  1. @Autowired
  2. private User user;
  3. @Test
  4. public void test() {
  5. System.out.println(this.user);
  6. }
  7. }
  8. 2. 这里使用的是Spring-test,然后省去了很多代码。
  9. * <dependency>
  10. <groupId>org.springframework</groupId>
  11. <artifactId>spring-test</artifactId>
  12. <version>4.3.21.RELEASE</version>
  13. </dependency>
  14. <dependency>
  15. <groupId>junit</groupId>
  16. <artifactId>junit</artifactId>
  17. <version>4.12</version>
  18. <scope>test</scope>
  19. </dependency>
  20. 2. ### setter注入 ###
  21. 1. 使用setXxx方法注入的方式,这里不提了。
  22. 3. ### 集合注入 ###
  23. 1. arraylistsetmapproperties注入。
  24. 2. <bean id="collectionDemo" class="com.fxyh.spring.di.CollectionDemo">
  25. <property name="arrayValue">
  26. <array>
  27. <value>zhangsan</value>
  28. <value>lisi</value>
  29. <value>wangwu</value>
  30. </array>
  31. </property>
  32. <property name="listValue">
  33. <list>
  34. <value>beijin</value>
  35. <value>shanghai</value>
  36. <value>hangzhou</value>
  37. <value>shenzhen</value>
  38. </list>
  39. </property>
  40. <property name="setValue">
  41. <set>
  42. <value>aaa</value>
  43. <value>bbb</value>
  44. <value>ccc</value>
  45. <value>ddd</value>
  46. </set>
  47. </property>
  48. <property name="mapValue">
  49. <map>
  50. <entry key="key1" value="111"/>
  51. <entry key="key2" value="222"/>
  52. <entry key="key3" value="333"/>
  53. <entry key="key4" value="444"/>
  54. </map>
  55. </property>
  56. <property name="properties">
  57. <props>
  58. <prop key="driverClassName">com.mysql.jdbc.Driver</prop>
  59. <prop key="url">jdbc:mysql:///fxyh</prop>
  60. <prop key="username">root</prop>
  61. <prop key="password">root</prop>
  62. </props>
  63. </property>
  64. </bean>
  65. 3. public class CollectionDemo implements Serializable {
  66. private static final long serialVersionUID = -4477381744799533624L;
  67. private String[] arrayValue;
  68. private List<String> listValue;
  69. private Set<String> setValue;
  70. private Map<String, Object> mapValue;
  71. private Properties properties;
  72. public String[] getArrayValue() {
  73. return arrayValue;
  74. }
  75. public void setArrayValue(String[] arrayValue) {
  76. this.arrayValue = arrayValue;
  77. }
  78. public List<String> getListValue() {
  79. return listValue;
  80. }
  81. public void setListValue(List<String> listValue) {
  82. this.listValue = listValue;
  83. }
  84. public Set<String> getSetValue() {
  85. return setValue;
  86. }
  87. public void setSetValue(Set<String> setValue) {
  88. this.setValue = setValue;
  89. }
  90. public Map<String, Object> getMapValue() {
  91. return mapValue;
  92. }
  93. public void setMapValue(Map<String, Object> mapValue) {
  94. this.mapValue = mapValue;
  95. }
  96. public Properties getProperties() {
  97. return properties;
  98. }
  99. public void setProperties(Properties properties) {
  100. this.properties = properties;
  101. }
  102. @Override
  103. public String toString() {
  104. return "CollectionDemo{" +
  105. "arrayValue=" + Arrays.toString(arrayValue) +
  106. ", listValue=" + listValue +
  107. ", setValue=" + setValue +
  108. ", mapValue=" + mapValue +
  109. ", properties=" + properties +
  110. '}';
  111. }
  112. }
  113. 4. ### 抽象Bean ###
  114. 1. 把公共的东西抽象出来,然后需要用到的使用parent
  115. 2. <bean id="abstractDemo" abstract="true">
  116. <property name="id" value="1"/>
  117. <property name="username" value="zhangsan"/>
  118. </bean>
  119. <bean id="abstractDemo1" class="com.fxyh.spring.di.AbstractDemo1" parent="abstractDemo">
  120. <property name="password" value="123456"/>
  121. </bean>
  122. <bean id="abstractDemo2" class="com.fxyh.spring.di.AbstractDemo2" parent="abstractDemo">
  123. <property name="age" value="22"/>
  124. </bean>
  125. <bean id="abstractDemo3" class="com.fxyh.spring.di.AbstractDemo3" parent="abstractDemo">
  126. <property name="address" value="jiangxi"/>
  127. <property name="id" value="2"/>
  128. </bean>
  129. 3. 这里abstractDemo是抽象Bean,然后使用parent对应这个则对应的属性就会被赋值,并且在自己的bean中重新给这个属性赋值了,那么这个属性将会把抽象bean中的属性的值给覆盖掉。
  130. 5. ### 自定义属性编辑器 ###
  131. 1. `no matching editors or conversion strategy found`
  132. 2. 比如我注入的时候注入时间,我直接写字符串的时间,然后这肯定是会报错的,就上面说的那个错误,无法注入。
  133. 3. 所以我们需要自定义属性编辑器。
  134. 4. import org.apache.commons.lang3.time.DateUtils;
  135. import java.beans.PropertyEditorSupport;
  136. import java.text.ParseException;
  137. import java.util.Date;
  138. public class CustomDatePropertyEditor extends PropertyEditorSupport {
  139. @Override
  140. public void setAsText(String text) throws IllegalArgumentException {
  141. Date date = null;
  142. try {
  143. date = DateUtils.parseDate(text, "yyyy-MM-dd");
  144. } catch (ParseException e) {
  145. e.printStackTrace();
  146. }
  147. this.setValue(date);
  148. }
  149. }
  150. 5. <bean id="person" class="com.fxyh.spring.di.Person">
  151. <property name="id" value="1"/>
  152. <property name="username" value="zhangsan"/>
  153. <property name="salary" value="#{10*new java.util.Random().nextInt(10)}"/>
  154. <property name="createDate" value="2019-06-30"/>
  155. </bean>
  156. <bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
  157. <property name="customEditors">
  158. <map>
  159. <entry key="java.util.Date" value="com.fxyh.spring.di.CustomDatePropertyEditor"/>
  160. </map>
  161. </property>
  162. </bean>
  163. 6. 自定义属性编辑器我们需要继承PropertyEditorSupport类,然后重写它的setAsText方法。现在已经不推荐使用了,推荐使用自定义转换器。
  164. 6. ### 自定义转换器 ###
  165. 1. 实现Converter接口,注意:`org.springframework.core.convert.converter.Converter`包路径。
  166. 2. 然后实现convert方法,在里面写对应的逻辑。
  167. 3. import org.apache.commons.lang3.StringUtils;
  168. import org.apache.commons.lang3.time.DateUtils;
  169. import org.springframework.core.convert.converter.Converter;
  170. import java.text.ParseException;
  171. import java.util.Date;
  172. public class CustomDateConverter implements Converter<String, Date> {
  173. private String[] parsePatterns;
  174. public void setParsePatterns(String[] parsePatterns) {
  175. this.parsePatterns = parsePatterns;
  176. }
  177. @Override
  178. public Date convert(String source) {
  179. Date date = null;
  180. if (StringUtils.isBlank(source)){
  181. throw new IllegalArgumentException("");
  182. }
  183. try {
  184. date = DateUtils.parseDate(source, this.parsePatterns);
  185. } catch (ParseException e) {
  186. e.printStackTrace();
  187. }
  188. return date;
  189. }
  190. }
  191. 4. <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
  192. <property name="converters">
  193. <set>
  194. <bean class="com.fxyh.spring.di.CustomDateConverter">
  195. <property name="parsePatterns">
  196. <array>
  197. <value>yyyy-MM-dd</value>
  198. <value>yyyy/MM/dd</value>
  199. </array>
  200. </property>
  201. </bean>
  202. </set>
  203. </property>
  204. </bean>
  205. 5. 这里注意这个转换器beanid,我用其他的试都是没用,只有把id改成conversionService才能使用。
  • ByName&ByType

    • ByName:根据名称匹配
    • ByType:根据类型匹配
    • 这里有个比较经典的异常Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.fxyh.spring.dao.UserDao' available: expected single matching bean but found 2: userDao111111,userDao
    • 这个接口有两个实现类,然后现在spring不知道选择哪个实现类注入就报这个异常了。
    • <?xml version=”1.0” encoding=”UTF-8”?>







    • 这里在beans上使用了default-autowire为byType,所以这个beans下的bean都会根据类型自动注入,而此时有userDao和userDao111111都是实现了UserDao接口,所以两个都符合要求,然后bean就不知道要注入哪一个了,而这里我们又在userService配置了autowire为byName,此时userService是根据名称来匹配的,则只有userDao一个匹配成功。(这里提供setter方法,然后把setter方法set去掉,然后第一个字母小写,就是名称)
    • 同时在配置中局部配置优先于全局配置!
  • 注解编程

    • @Autowired

      • 属于Spring框架的注解
      • 先按类型匹配,如果匹配不到再按名称匹配
    • @Resource

      • 属于JavaEE规范的注解
      • 先按名称匹配,如果匹配不到再按类型匹配
    • @Qualifier

      • 和@Autowired结合使用的时候,按照类型匹配,不按类型匹配。
      • @Resource原本就是按名称所以在它按名称找不到的时候,使用@Qualifier设置的名称匹配。
    • @Component

      • 把这个类注解为一个组件
    • @Repository

      • 数据库交互层使用的注解(Dao)
    • @Service

      • 服务层使用的注解
    • @Controller

      • 控制层使用的注解
    • @Configuration

      • 配置类注解
    • @Bean

      • 把这个方法注解成一个创建bean的方法。
    • 使用注解开发首先不能少了组件扫描,开启开关。

      • <?xml version=”1.0” encoding=”UTF-8”?>





    • 这里不贴测试用例了,自己写写测试用例测一测就ok了。

发表评论

表情:
评论列表 (有 0 条评论,318人围观)

还没有评论,来说两句吧...

相关阅读

    相关 DI依赖注入

    在DI(依赖注入)中,能注入的数据是有三种类型的: 1、基本类型和String 2、其他bean类型(在配置文件中或者注解配置过的bean对象) 3、复杂类型/集

    相关 Spring依赖注入DI

    开头语:本文是我整理网上各种资料后整合而成的一篇文章。文中涉及到了代码重构、面向接口编程、持久化和工厂设计模式的内容。 1. Spring是什么?

    相关 SpringIOC/DI

    spring笔记 高内聚低耦合: 工厂模式:通过第三方的类产生我们需要的产品(对象),用来解耦合 简单工厂: 1. 提供产品接口,之后让所有产品实现该接口 2.

    相关 依赖注入2-DI

    IoC主要体现了这样一种设计思想:通过将一组通用流程的控制从应用转移到框架之中以实现对流程的复用,同时采用“好莱坞原则”是应用程序以被动的方式实现对流程的定制。我们可以采用若干