IT评测·应用市场-qidao123.com

标题: spring IOC(实现原理) [打印本页]

作者: 丝    时间: 2025-3-9 15:33
标题: spring IOC(实现原理)
依赖注入

**依赖注入(DI)**是Spring框架核心功能之一,它允许对象间的依赖关系通过配置或代码在运行时动态注入,而不是通过对象内部硬编码。这种方法淘汰了代码间的耦合,增加了灵活性和可重用性。
依赖注入强调的是对象的依赖关系由外部来管理和提供,而不是由对象自身负责创建依赖对象。通过这种方式,可以低沉对象之间的耦合度。即下面的方式也属于依赖注入。
常见的依赖注入方式

  1. public class ProductService {
  2.     private final ProductRepository productRepository;
  3.     public ProductService(ProductRepository productRepository) {
  4.         this.productRepository = productRepository;
  5.     }
  6.     // 业务方法
  7. }
复制代码

  1. public class UserService {
  2.     private UserRepository userRepository;
  3.     public void setUserRepository(UserRepository userRepository) {
  4.         this.userRepository = userRepository;
  5.     }
  6.     // 业务方法
  7. }
复制代码
xml依赖注入

  1. ---------------Student类------------------
  2. public class Student {
  3.     private String name;
  4.     private Adress address;
  5.     private String[] books;
  6.     private List<String> hobbies;
  7.     private Map<String,String> card;
  8.     private Set<String> games;
  9.     private String wife;
  10.     private Properties info;
  11.     //getter,setter,无参and全参构造
  12.     }
  13. ---------------Teacher类------------------
  14. public class Teacher {
  15.     private String name;
  16.     private int age;
  17.     //getter,setter,无参and全参构造
  18.     }
  19. ---------------applicationContext.xml------------------
  20.   <bean id="adress" class="com.luxiya.Adress">
  21.         <property name="address" value="空中花园"/>
  22.     </bean>
  23.    <!-- 需要相应的构造函数-->
  24.     <bean id="teacher" class="com.luxiya.Teacher" c:name="luxiya" c:age="18"/>
  25.     <!-- 需要相应的构造函数-->
  26.     <bean id="teacher1" class="com.luxiya.Teacher">
  27.         <constructor-arg name="name" value="luxiya-constructor"/>
  28.         <constructor-arg name="age" value="188"/>
  29.     </bean>
  30.     <!-- 需要空参构造-->
  31.     <bean id="teacher2" class="com.luxiya.Teacher" p:name="zhihuiguan" p:age="19">
  32.     </bean>
  33.     <bean id="student" class="com.luxiya.Student">
  34.         <property name="name" value="luxiya"/>
  35.         <property name="address" ref="adress"/>
  36.         <property name="books">
  37.             <array>
  38.                 <value>java</value>
  39.                 <value>python</value>
  40.             </array>
  41.         </property>
  42.         <property name="hobbies">
  43.             <list>
  44.                 <value>打篮球</value>
  45.                 <value>打游戏</value>
  46.             </list>
  47.         </property>
  48.         <property name="card">
  49.             <map>
  50.                 <entry key="身份证" value="123456789"/>
  51.                 <entry key="银行卡" value="123456789"/>
  52.             </map>
  53.         </property>
  54.         <property name="games">
  55.             <set>
  56.                 <value>LOL</value>
  57.                 <value>DOTA</value>
  58.             </set>
  59.         </property>
  60.         <property name="wife">
  61.             <null/>
  62.         </property>
  63.         <property name="info">
  64.             <props>
  65.                 <prop key="name">luxiya</prop>
  66.                 <prop key="age">18</prop>
  67.             </props>
  68.         </property>
  69.     </bean>
  70. ---------------测试类------------------
  71. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  72. Student student = (Student) context.getBean("student");
  73. System.out.println(student.toString());
  74. Teacher teacher = (Teacher) context.getBean("teacher");
  75. System.out.println(teacher.toString());
  76. Teacher teacher1 = (Teacher) context.getBean("teacher1");
  77. System.out.println(teacher1.toString());
  78. Teacher teacher2 = (Teacher) context.getBean("teacher2");
  79. System.out.println(teacher2.toString());
复制代码
控制反转

​ 在传统的程序计划中,当一个对象(A)需要使用另一个对象(B)的功能时,通常会在对象 A 内部主动创建对象 B 的实例,即对象 A 对对象 B 的创建和生命周期管理具有控制权。而在控制反转的头脑下,对象 A 所依赖的对象 B 的创建、实例化以及依赖关系的建立,不再由对象 A 自身负责,而是由一个外部的容器(比如 Spring 容器)来负责管理。如许一来,对象 A 得到依赖对象 B 的过程被反转了,控制权从对象 A 转移到了外部容器,这就是 “控制反转” 名称的由来。
​ IoC 容器负责创建对象、管理对象的生命周期,并在得当的时候将对象注入到需要它们的其他对象中。应用程序中的各个组件(对象)只需要关注自身的业务逻辑,而不需要关心依赖对象的创建和获取过程。容器会根据配置信息(如 XML 配置文件或注解)来确定对象之间的依赖关系,并自动完成对象的实例化和注入。

相关

ApplicationContext 接口,工厂的接口,使用该接口可以获取到详细的 Bean 对象。该接口下有两个详细的实现类。
ClassPathXmlApplicationContext,加载类路径下的 Spring 配置文件。(注:ClassPathXmlApplicationContext在读取application.xml文件时,就会自动创建bean实例)
FileSystemXmlApplicationContext,加载当地磁盘下的 Spring 配置文件。
Spring 框架的 Bean管理的配置文件方式

id 属性为每个 Bean 提供了一个唯一的标识符。
class 属性指定了 Bean 对象的全限定类名。在这个例子中,com.example.service.UserService 就是 UserService 类的完整路径,Spring 容器会根据这个路径来创建相应的 Bean 实例。


  1.     <!-- 定义一个单例的 UserService Bean -->
  2.     <bean id="userServiceSingleton" class="com.example.service.UserService"
  3.           scope="singleton"
  4.           init-method="init"
  5.           destroy-method="destroy">
  6.     </bean>
  7.     <!-- 定义一个多例的 UserService Bean -->
  8.     <bean id="userServicePrototype" class="com.example.service.UserService"
  9.           scope="prototype">
  10.     </bean>
  11. -----------------测试------------------
  12. public class UserService {
  13.     // 初始化方法
  14.     public void init() {
  15.         System.out.println("UserService 初始化");
  16.     }
  17.     // 销毁方法
  18.     public void destroy() {
  19.         System.out.println("UserService 销毁");
  20.     }
  21. }
复制代码
实例化Bean的三种方式

无参构造器实例化

这是 Spring 中最基本的实例化 Bean 的方式,Spring 容器会调用 Bean 类的无参构造器(假如没有指定其他构造器)或者指定的有参构造器来创建 Bean 对象。
  1. public class UserService {
  2.     public UserService() {
  3.         System.out.println("UserService实例化");
  4.     }
  5. }
  6. -------------application.xml--------------
  7. <bean id="userService" class="com.luxiya.demo.UserService"/>
  8. -------------测试类--------------
  9.         ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  10.         UserService userService = (UserService) context.getBean("userService");
复制代码
静态工厂方法实例化

使用一个静态工厂方法来创建 Bean 对象。静态工厂方法是类中的一个静态方法,该方法会返回一个对象实例。Spring 容器会调用这个静态工厂方法来获取 Bean 对象。
  1. public class StaticFactory {
  2.     public static UserService getUserService()
  3.     {
  4.         System.out.println("静态工厂创建");
  5.         return new UserService();
  6.     }
  7. }
  8. -------------application.xml--------------
  9.     <!-- 静态工厂-->
  10.     <bean id="uSstatic" class="com.luxiya.demo.StaticFactory" factory-method="getUserService"/>
  11. -------------测试类--------------
  12.         ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  13.         UserService userService = (UserService) context.getBean("uSstatic");
复制代码
实例工厂方法实例化

使用一个实例工厂的方法来创建 Bean 对象。起首需要创建一个工厂类的实例,然后调用该实例的方法来创建 Bean 对象。
  1. -------------application.xml--------------
  2. <!--动态工厂-->
  3. <bean id="dFactory" class="com.luxiya.demo.DFactory"/>
  4. <bean id="useDF" factory-bean="dFactory" factory-method="getUserService"/>
  5. -------------测试类--------------
  6. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  7. UserService userService = (UserService) context.getBean("useDF");
复制代码
静态和动态对比


注解

常用注解

@Component 普通的类
@Controller 表现层@Service 业务层
@Repository 长期层
依赖注入常用的注解
@Value 用于注入普通范例(String,int,double 等范例)
@Autowired 默认按范例举行自动装配(引用范例)
@Qualifier 和@Autowired 一起使用,强制使用名称注入
@Resource Java 提供的注解,也被支持。使用 name 属性,按名称注入
对象生命周期(作用范围)注解
@Scope 生命周期注解,取值 singleton(默认值,单实例)和 prototype(多
例)
初始化方法和销毁方法注解(相识)
@PostConstruct 相当于 init-method
@PreDestroy 相当于 destroy-method
  1. @Service
  2. public class TeacherService {
  3.     public TeacherService() {
  4.         System.out.println("TeacherService初始化");
  5.     }
  6. }
  7. -----------application.xml----------
  8. <!--开启注解扫描-->
  9. <context:component-scan base-package="com.luxiya.demo"/>
  10. -----------------测试类--------------
  11. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  12. TeacherService teacherService = (TeacherService) context.getBean("teacherService");
复制代码
纯注解

纯注解的方式是微服务架构开辟的主要方式,所以也黑白常的紧张。纯注解的目标是替换掉全部的配置文件。但是需要编写配置类。
常用的注解总结
@Configuration 声明是配置类
@ComponentScan 扫描详细包结构的。也可以扫描多个包@ComponentScan(value ={“com.qcbyjy.demo4”,“com.qcbyjy.demo3”})
@Import 注解 Spring 的配置文件可以分成多个配置的,编写多个配置类。用于导入其他配置类
@Bean 注解 只能写在方法上,表明使用此方法创建一个对象,对象创建完成保存到 IOC 容器中
  1. ------------demo包下的配置类--------------
  2. @Configuration
  3. @ComponentScan(basePackages = "com.luxiya.demo")
  4. @Import(SpringConfig2.class)
  5. public class SpringCofig {
  6.     @Bean(name="dataSource")
  7.     public DataSource createDataSource(){
  8.         DruidDataSource dataSource = new DruidDataSource();
  9.         dataSource.setDriverClassName("com.mysql.jdbc.Driver");
  10.         dataSource.setUrl("jdbc:mysql:///spring_db");
  11.         dataSource.setUsername("root");
  12.         dataSource.setPassword("root");
  13.         return dataSource;
  14.     }
  15. }
  16. -------------------基础测试--------------
  17.         ApplicationContext context = new AnnotationConfigApplicationContext(SpringCofig.class);
  18.         Student student = (Student) context.getBean("student");
  19. -------------demo2包下的配置类----------------
  20. @Configuration
  21. @ComponentScan(basePackages = "com.luxiya.demo2")
  22. public class SpringConfig2 {
  23. }
  24. //demo2包下
  25. @Data
  26. @Component
  27. public class Course {
  28.     @Value("java")
  29.     private String name;
  30.     public Course()
  31.     {
  32.         System.out.println("Course初始化");
  33.     }
  34. }
  35. //demo包下
  36. @Component
  37. @Data
  38. public class Student {
  39.     @Value("luxiya")
  40.     private String name;
  41.     public Student() {
  42.         System.out.println("Student实例化");
  43.     }
  44. }
  45. ------------测试@Import注解-------------
  46.         ApplicationContext context = new AnnotationConfigApplicationContext(SpringCofig.class);
  47.         Course course = (Course) context.getBean("course");
  48.         
  49. ------------测试@Bean注解-------------
  50.                 ApplicationContext context = new AnnotationConfigApplicationContext(SpringCofig.class);
  51. //        Student student = (Student) context.getBean("student");
  52. //        Course course = (Course) context.getBean("course");
  53.         // 从应用上下文中获取 DataSource 对象
  54.         DataSource dataSource = context.getBean("dataSource", DataSource.class);
  55.         // 验证 DataSource 对象是否为 DruidDataSource 类型
  56.         if (dataSource instanceof DruidDataSource) {
  57.             DruidDataSource druidDataSource = (DruidDataSource) dataSource;
  58.             System.out.println("Druid DataSource 配置信息:");
  59.             System.out.println("Driver Class Name: " + druidDataSource.getDriverClassName());
  60.             System.out.println("URL: " + druidDataSource.getUrl());
  61.             System.out.println("Username: " + druidDataSource.getUsername());
  62.             System.out.println("Password: " + druidDataSource.getPassword());
  63.         }
复制代码
别的问题

为什么p 定名空间方式需要无参构造

缘故原由:在 Spring 中,当你使用属性注入(如你给出的 p 定名空间方式)时,Spring 容器在创建 Bean 实例的过程中,默认情况下会尝试使用无参构造函数来实例化对象,之后再通过 setter 方法举行属性注入。
Spring 容器在创建 Bean 实例时,主要有以下几个步调:
所以,当你使用 p 定名空间举行属性注入时,Spring 起首会尝试调用无参构造函数来创建 Teacher 对象,若类中没有无参构造函数,就会抛出 No default constructor found 如许的异常。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) Powered by Discuz! X3.4