【Spring】DI:四种依赖注入方式(包括xml、注解)

矫情吗;* 2022-12-26 00:50 292阅读 0赞

DI(DependencyInjection)依赖注入:就是指对象是被动接受依赖类而不是自己主动去找,换句话说就。是指对象不是从容器中查找它依赖的类,而是在容器实例化对象的时候主动将它依赖的类注入给它。

1.setter注入

  1. public class Student {
  2. private String name;
  3. private Teacher teacher;
  4. public String getName() {
  5. return name;}
  6. public void setName(String name) {
  7. this.name = name;}
  8. public Teacher getTeacher() {
  9. return teacher; }
  10. public void setTeacher(Teacher teacher) {
  11. this.teacher = teacher; }
  12. }
  13. public class Teacher {
  14. private String name;
  15. public String getName() {
  16. return name; }
  17. public void setName(String name) {
  18. this.name = name; }
  19. }

1.xml形式

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!-- 创建一个id=teacher的Teacher -->
  7. <bean id="teacher" class="test.Teacher">
  8. <property name="name" value="李四"/>
  9. </bean>
  10. <!-- 创建一个id=student的Student -->
  11. <bean id="student" class="test.Student">
  12. <property name="name" value="张三"/>
  13. <!-- 将teacher注给student -->
  14. <property name="teacher" ref="teacher"/>
  15. </bean>
  16. </beans>

两点注意:

  • set 方法必须 public
  • property 中的 name 必须与 set 方法参数名一致,而不是与成员变量名一致

2.注解

  1. @Configuration
  2. public class BeansConfiguration {
  3. @Bean
  4. // 这个bean的name=student
  5. public Student student(){
  6. Student student=new Student();
  7. student.setName("张三");
  8. student.setTeacher(teacher());
  9. return student;
  10. }
  11. @Bean
  12. // name=student
  13. public Teacher teacher(){
  14. Teacher teacher=new Teacher();
  15. teacher.setName("李四");
  16. return teacher;
  17. }
  18. }
  19. public class Main {
  20. public static void main(String args[]){
  21. FileSystemXmlApplicationContext context=new
  22. FileSystemXmlApplicationContext("applicationContext.xml的绝对路径");
  23. // 容器中拿出来的student张三就是被注入过student的
  24. Student student= (Student) context.getBean("student");
  25. Teacher teacher= (Teacher) context.getBean("teacher");
  26. System.out.println("学生的姓名:"+student.getName()+"。老师
  27. 是"+student.getTeacher().getName());
  28. System.out.println("老师的姓名:"+teacher.getName());
  29. }
  30. }

2.构造器注入

  1. public class Student {
  2. private String name;
  3. private Teacher teacher;
  4. public Student(String name,Teacher teacher) {
  5. this.name = name;
  6. this.teacher = teacher;
  7. }
  8. }
  9. public class Teacher {
  10. private String name;
  11. public String getName() {
  12. return name; }
  13. public void setName(String name) {
  14. this.name = name; }
  15. }

1.xml形式

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!-- 创建Teacher实例teacher -->
  7. <bean name="teacher" class="test.Teacher">
  8. <property name="name" value="李四"></property>
  9. </bean>
  10. <bean name="student" class="test.Student">
  11. <!-- 注入 teacher 这个 bean -->
  12. <constructor-arg ref="teacher" />
  13. </bean>
  14. </beans>

2.注解

  1. @Configuration
  2. public class MainConfig {
  3. // 这个bean没必要注入IOC容器
  4. public Teacher teacher() {
  5. return new Teacher();
  6. teacher.setName = "李四";
  7. }
  8. // 创建一个bean student
  9. @Bean
  10. public Student student() {
  11. return new Student(teacher());
  12. }
  13. }

3.自动注入

自动注入就是根据当前对象中定义的实例变量名进行注入

1.xml形式:byName + byType

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!-- 创建Teacher实例teacher -->
  7. <bean id="teacher" class="test.Teacher">
  8. <property name="name" value="李四"/>
  9. </bean>
  10. <!-- 创建Student实例student -->
  11. <!-- byName 会自动给未初始化实例变量找能匹配的bean注入进来 -->
  12. <bean id="student" class="test.Student" autowire="byName">
  13. <property name="name" value="张三"/>
  14. </bean>
  15. </beans>

2.注解形式:@Autowired + @Value

注:如果要使用注解,必须要先在开启(<context:annotation-config/),但是一般使用 <context:component-scan> 在开启注解的同时指定要扫描的包

@Autowired

  • 自动装配时按照类型进行装配,若在IOC容器中发现多个相同类型的组件,那么就按照 @Qualifier 配置的属性名称来进行装配
  • @Qualifier(“name”):可以在容器中有多个同一类的bean时指定name。比如 Teacher有teacher1,teacher2,那么我们就可以 @Autowired @Qualifier(“teacher1”) 指定teacher1注入。

对比 @Autowired 和 @Resource:

  • 共同点:@Resource和@Autowired都可以作为注入属性的修饰,在接口仅有单一实现类时,两个注解的修饰效果相同,可以互相替换,不影响使用。
  • 不同点:

    • @Autowired是spring的注解,是spring2.5版本引入的,Autowired只根据type进行注入,不会去匹配name。如果涉及到type无法辨别注入对象时,那需要依赖@Qualifier或@Primary注解一起来修饰。
    • @Resource 是JDK1.6支持的注解, 默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取类名首字母小写,然后按照名称查找。如果注解写在setter方法上默认取属性名进行装配。
      当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

一般推荐使用 @Autowired,当需要指定 beanName 时再用 @Resource。

@Value

  • @Value(value):给当前变量直接注入指定值value,类型要对应
  • @Value(“#{configProperties[‘key’]}“):表示SpEl表达式通常用来获取bean的属性,或者调用bean的某个方法。当然还有可以表示常量
  • @Value(“${key}“):可以获取对应属性文件中定义的属性值。

    // 将Teacher的实例teacher注入IOC容器
    @Component(“teacher”)
    public class Teacher {

  1. @Value("李四") // 为name注入String值,李四
  2. private String name;
  3. public String getName() {
  4. return name;
  5. }
  6. public void setName(String name) {
  7. this.name = name;
  8. }
  9. }
  10. // 将Student实例student注入IOC容器
  11. @Component("student")
  12. public class Student {
  13. @Value("张三")
  14. private String name; // name = 张三
  15. @Resource
  16. private Teacher teacher; // 通过名字 teacher 去寻找bean,找到了注入进去
  17. public String getName() {
  18. return name;
  19. }
  20. public void setName(String name) {
  21. this.name = name;
  22. }
  23. public Teacher getTeacher() {
  24. return teacher;
  25. }
  26. public void setTeacher(Teacher teacher) {
  27. this.teacher = teacher;
  28. }
  29. }

注:对于静态成员的注入,不能将注解直接打在成员变量上,而是在 setter 上

  1. // 静态成员
  2. private static String domain;
  3. // 通过setter注入
  4. @Value("${xusm.domain}")
  5. public void setDatabase(String d) {
  6. domain = d;
  7. }

4.依赖方法注入(lookup-method)

当一个单例的Bean,依赖于一个多例的Bean,用常规方法只会被注入一次,如果每次都想要获取一个全新实例就可以采用lookup-method 方法来实现。该操作的原理是基于动态代理技术,重新生成一个继承至目标类,然后重写抽像方法到达注入目的。

前面说所单例Bean依赖多例Bean这种情况也可以通过实现 ApplicationContextAware 、BeanFactoryAware 接口来获取BeanFactory 实例,从而可以直接调用getBean方法获取新实例,推荐使用该方法,相比lookup-method语义逻辑更清楚一些。

  1. <bean id="MethodInject" class="com.my.spring.MethodInject">
  2. <lookup-method name="getFine" bean="fine"></lookup-method>
  3. </bean>
  4. // 编写一个抽像类
  5. public abstract class MethodInject {
  6. public void handlerRequest() {
  7. // 通过对该抽像方法的调用获取最新实例
  8. getFine();
  9. }
  10. // 编写一个抽像方法
  11. public abstract FineSpring getFine();
  12. }
  13. // 设定抽像方法实现

发表评论

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

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

相关阅读

    相关 spring依赖注入方式

    平常的java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注

    相关 spring依赖注入方式

    平常的java开发中,程序员在某个类中需要依赖其它类的方法,通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理。 spring提出了依赖