Spring——IoC中基于注解的DI

简介: Spring——IoC中基于注解的DI

文章目录:


1.基于注解的DI概述

1.1 使用多个 context:component-scan 指定不同的包路径

1.2 指定 base-package 的值使用分隔符

1.3 base-package 指定到父包名

2.注解的使用

2.1 @Component@Value(存在于Spring中,用于给简单类型的属性赋值)

2.2 @Autowired(存在于Spring中,用于给引用类型的属性赋值,byType

2.3 @Autowired@Qualifier(存在于Spring中,用于给引用类型的属性赋值,byName

2.4 @Resource(存在于jdk中,用于给引用类型的属性赋值)

3.对比——基于XMLDI和基于注解的DI

3.1 XML方式的优缺点 

3.2 注解方式的优缺点 

3.3 总体来说,DI还是以注解为主,XML为辅 

4.Spring IoC总结 


1.基于注解的DI概述


在这里我们主要介绍以下几种注解:👇👇👇

1.    创建对象的注解:@Component@Repository@Service@Controller。(来自Spring框架)

2.    简单类型的对象属性赋值:@Value。(来自Spring框架)

3.    引用类型的对象属性赋值:@Autowired@Qualifier。(来自Spring框架)

4.    引用类型的对象属性赋值:@Resource。(来自JDK

对于 DI 使用注解,将不再需要在 Spring 配置文件中声明 bean 实例。Spring 中使用注解,需要在原有 Spring 运行环境基础上再做一些改变。需要在 Spring 配置文件中配置组件扫描器,用于在指定的基本包中扫描注解。 

在基于注解的DI中,我们的Spring配置文件中将不再需要<bean>标签,而是在其中添加

<context:component-scan base-package="XXX" /> 这句代码。

在指定的包中扫描注解一共有以下三种方式:👇👇👇


1.1 使用多个context:component-scan 指定不同的包路径

<!--
    声明组件扫描器:使用注解必须加上这个语句
    component-scan: 组件扫描器,组件是Java对象
    属性base-package: 表示项目中的包名
    框架会扫描这个包和子包中的所有类,找到类中的所有注解,
    遇到注解后,按照注解表示的功能,去创建对象、给属性赋值
-->
<context:component-scan base-package="com.bjpowernode.ba01" />
<context:component-scan base-package="com.bjpowernode.ba02" />

1.2 指定 base-package 的值使用分隔符

<!-- 可以使用分隔符(;或者,)指定多个包 -->
<context:component-scan base-package="com.bjpowernode.ba01;com.bjpowernode.ba02" />
<context:component-scan base-package="com.bjpowernode.ba01,com.bjpowernode.ba02" />

1.3 base-package 指定到父包名

base-package的值表是基本包,容器启动会扫描包及其子包中的注解,当然也会扫描到子包下级的子包。所以 base-package 可以指定一个父包就可以。 但不建议使用顶级的父包,扫描的路径比较多,导致容器启动时间变慢。

<!-- 也可以指定父包 -->
<context:component-scan base-package="com.bjpowernode" />

2.注解的使用


2.1 @Component@Value(存在于Spring中,用于给简单类型的属性赋值)

@Component: 表示创建对象,对象放到容器中,作用是 <bean>
         
属性: value,表示对象名称,也就是 <bean> 标签中的 id 属性值
         
位置: 在类的上面,表示创建此类的对象

@Component功能相同的创建对象的注解:

1.    @Repository : 放在dao接口的实现类上面,表示创建dao对象,能访问数据库

2.    @Service : 放在业务层接口的实现类上面,表示创建业务层对象,具有事务的功能

3.    @Controller : 放在控制器类的上面,表示创建控制器对象,能够接收请求,把请求的处理结果显示给用户

@Repository@Service@Controller 是对@Component注解的细化,标注不同层的对象。

简单类型的属性赋值:@Value
     
属性: value,表示属性值,可以省略
     
位置:1) 在属性定义的上面,无需set方法,推荐使用
                 2)
set方法上面

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="com.bjpowernode.ba01" />
</beans>
package com.bjpowernode.ba01;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
 *  @Component: 表示创建对象,对象放到容器中,作用是 <bean>
 *         属性: value,表示对象名称,也就是 <bean> 标签中的 id 属性值
 *         位置: 在类的上面,表示创建此类的对象
 *
 *  @Component(value = "myStudent") 等同于
 *  @Component("myStudent") 等同于
 *  <bean id="myStudent" class="com.bjpowernode.ba01.Student" />
 *
 *  如果写成 @Component,则会使用框架的默认对象名称(类名首字母小写student)
 */
@Component("myStudent")
public class Student {
    /**
     *  简单类型的属性赋值:@Value
     *  属性: value,表示属性值,可以省略
     *  位置:1)在属性定义的上面,无需set方法,推荐使用
     *       2)在set方法上面
     */
    @Value("张三")
    private String name;
    @Value("20")
    private int age;
    public Student() {
        System.out.println("Student类的无参构造方法被执行了");
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
package com.bjpowernode;
import com.bjpowernode.ba01.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 *
 */
public class MyTest {
    @Test
    public void test01() {
        String config="applicationContext.xml";
        ApplicationContext ctx=new ClassPathXmlApplicationContext(config);
        Student student= (Student) ctx.getBean("myStudent");
        System.out.println("student === " + student);
    }
}

2.2 @Autowired(存在于Spring中,用于给引用类型的属性赋值,byType

引用类型:@Autowired

spring框架提供的,给引用类型赋值的,使用自动注入原理。支持byNamebyType,默认是byType

属性:requiredboolean类型的属性,默认为true
           true
spring在创建容器对象时,会检查引用类型是否赋值成功,如果赋值失败,终止程序运行并报错。
           false
:如果引用类型赋值失败,程序正常执行不会报错,此时引用类型的值为null

位置:1)在属性定义的上面,无需set方法,推荐使用
          2)
set方法上面

byType自动注入:👇👇👇

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="com.bjpowernode.ba02"/>
</beans>
package com.bjpowernode.ba02;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
 *
 */
@Component("mySchool")
public class School {
    @Value("北京大学")
    private String name;
    @Value("北京海淀区")
    private String address;
    @Override
    public String toString() {
        return "School{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}
package com.bjpowernode.ba02;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("myStudent")
public class Student {
    @Value("张三")
    private String name;
    @Value("20")
    private int age;
    /**
     *  引用类型:@Autowired
     *  spring框架提供的,给引用类型赋值的,使用自动注入原理
     *  支持byName、byType,默认是byType
     *  属性:required:boolean类型的属性,默认为true
     *       true:spring在创建容器对象时,会检查引用类型是否赋值成功,如果赋值失败,终止程序运行并报错。
     *       false:如果引用类型赋值失败,程序正常执行不会报错,此时引用类型的值为null。
     *  位置:1)在属性定义的上面,无需set方法,推荐使用
     *       2)在set方法上面
     *  byType自动注入
     */
    @Autowired(required = true)
    private School school;
    public Student() {
        System.out.println("Student类的无参构造方法被执行了");
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", school=" + school +
                '}';
    }
}
package com.bjpowernode;
import com.bjpowernode.ba02.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 *
 */
public class MyTest02 {
    @Test
    public void test01() {
        String config="applicationContext02.xml";
        ApplicationContext ctx=new ClassPathXmlApplicationContext(config);
        Student student= (Student) ctx.getBean("myStudent");
        System.out.println("student === " + student);
    }
}

2.3 @Autowired@Qualifier(存在于Spring中,用于给引用类型的属性赋值,byName

引用类型:@Autowired

spring框架提供的,给引用类型赋值的,使用自动注入原理。支持byNamebyType,默认是byType

属性:requiredboolean类型的属性,默认为true
           true
spring在创建容器对象时,会检查引用类型是否赋值成功,如果赋值失败,终止程序运行并报错。
           false
:如果引用类型赋值失败,程序正常执行不会报错,此时引用类型的值为null

位置:1) 在属性定义的上面,无需set方法,推荐使用
         2)
set方法上面

byName自动注入:
      1) @Autowired
:给引用类型赋值
      2) @Qualifier(value="bean
id"):从容器中找到指定名称的对象,把这个对象赋值给引用类型 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="com.bjpowernode.ba03"/>
</beans>
package com.bjpowernode.ba03;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
 *
 */
@Component("mySchool")
public class School {
    @Value("清华大学")
    private String name;
    @Value("北京海淀区")
    private String address;
    @Override
    public String toString() {
        return "School{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}
package com.bjpowernode.ba03;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("myStudent")
public class Student {
    @Value("李四")
    private String name;
    @Value("25")
    private int age;
    /**
     *  引用类型:@Autowired
     *  spring框架提供的,给引用类型赋值的,使用自动注入原理
     *  支持byName、byType,默认是byType
     *  属性:required:boolean类型的属性,默认为true
     *       true:spring在创建容器对象时,会检查引用类型是否赋值成功,如果赋值失败,终止程序运行并报错。
     *       false:如果引用类型赋值失败,程序正常执行不会报错,此时引用类型的值为null。
     *  位置:1)在属性定义的上面,无需set方法,推荐使用
     *       2)在set方法上面
     *  byName自动注入:
     *  1)@Autowired:给引用类型赋值
     *  2)@Qualifier(value="bean的id"):从容器中找到指定名称的对象,把这个对象赋值给引用类型
     */
    @Autowired(required = true)
    @Qualifier(value = "mySchool")
    private School school;
    public Student() {
        System.out.println("Student类的无参构造方法被执行了");
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", school=" + school +
                '}';
    }
}
package com.bjpowernode;
import com.bjpowernode.ba03.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 *
 */
public class MyTest03 {
    @Test
    public void test01() {
        String config="applicationContext03.xml";
        ApplicationContext ctx=new ClassPathXmlApplicationContext(config);
        Student student= (Student) ctx.getBean("myStudent");
        System.out.println("student === " + student);
    }
}

2.4 @Resource(存在于jdk中,用于给引用类型的属性赋值)

引用类型:@Resource,来自jdk中,给引用类型赋值,支持byNamebyType,默认是byNameSpring框架支持这个注解。

位置:1) 在属性定义的上面,无需set方法,推荐使用
         2)
set方法上面

@Resource:先使用byName赋值,如果赋值失败,再使用byType
@Resource(name="mySchool")
:表示只使用byName

如果使用jdk1.8,则带有@Resource注解;如果高于jdk1.8,则没有这个注解。如需使用,需要在pom.xml文件中加入依赖:👇👇👇

<dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>javax.annotation-api</artifactId>
    <version>1.3.2</version>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="com.bjpowernode.ba04"/>
</beans>
package com.bjpowernode.ba04;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
 *
 */
@Component("mySchool")
public class School {
    @Value("北京大学")
    private String name;
    @Value("北京海淀区")
    private String address;
    @Override
    public String toString() {
        return "School{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}
package com.bjpowernode.ba04;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component("myStudent")
public class Student {
    @Value("张起灵")
    private String name;
    @Value("18")
    private int age;
    /**
     *  引用类型:@Resource,来自jdk中,给引用类型赋值,支持byName、byType,默认是byName
     *  位置:1)在属性定义的上面,无需set方法,推荐使用
     *       2)在set方法上面
     *  @Resource:先使用byName赋值,如果赋值失败,再使用byType
     *  @Resource(name="mySchool"):表示只使用byName
     *  如果使用jdk1.8,则带有@Resource注解;
     *  如果高于jdk1.8,则没有这个注解。如需使用,需要在pom.xml文件中加入依赖
     */
    @Resource
    private School school;
    public Student() {
        System.out.println("Student类的无参构造方法被执行了");
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", school=" + school +
                '}';
    }
}
package com.bjpowernode;
import com.bjpowernode.ba04.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 *
 */
public class MyTest04 {
    @Test
    public void test01() {
        String config="applicationContext04.xml";
        ApplicationContext ctx=new ClassPathXmlApplicationContext(config);
        Student student= (Student) ctx.getBean("myStudent");
        System.out.println("student === " + student);
    }
}


3.对比——基于XML的DI和基于注解的DI


3.1 XML方式的优缺点 

优点:配置和代码是相分离的。

           xml中做修改,无需编译代码,只需重启服务器即可将新的配置加载。

缺点:编写麻烦,效率低,如果面对大型项目就显得过于复杂。


3.2 注解方式的优缺点 

优点:方便、直观、高效(代码少,没有配置文件的书写那么复杂) 

缺点:以硬编码的方式写入到 Java 代码中,修改是需要重新编译代码的。


3.3 总体来说,DI还是以注解为主,XML为辅 

4.Spring IoC总结


IoC用来管理对象,把对象放在容器中,进而创建对象、给对象属性赋值、管理对象之间的依赖关系。

IoC通过管理对象实现解耦合。往往解决的是业务逻辑对象之间的耦合关系,也就是servicedao之间的解耦合。

适合交给Spring容器的对象:service对象、dao对象、工具类对象。

不适合交给Spring容器的对象:实体类,servletlistenerfilterweb中的对象(它们是由tomcat创建和管理的)。

相关文章
|
6天前
|
运维 Java 程序员
Spring5深入浅出篇:基于注解实现的AOP
# Spring5 AOP 深入理解:注解实现 本文介绍了基于注解的AOP编程步骤,包括原始对象、额外功能、切点和组装切面。步骤1-3旨在构建切面,与传统AOP相似。示例代码展示了如何使用`@Around`定义切面和执行逻辑。配置中,通过`@Aspect`和`@Around`注解定义切点,并在Spring配置中启用AOP自动代理。 进一步讨论了切点复用,避免重复代码以提高代码维护性。通过`@Pointcut`定义通用切点表达式,然后在多个通知中引用。此外,解释了AOP底层实现的两种动态代理方式:JDK动态代理和Cglib字节码增强,默认使用JDK,可通过配置切换到Cglib
|
12天前
|
Java 测试技术 开发者
Spring IoC容器通过依赖注入机制实现控制反转
【4月更文挑战第30天】Spring IoC容器通过依赖注入机制实现控制反转
22 0
|
2天前
|
JSON 前端开发 Java
【JAVA进阶篇教学】第七篇:Spring中常用注解
【JAVA进阶篇教学】第七篇:Spring中常用注解
|
3天前
|
Java Spring 容器
Spring05 SpringIOC & DI
Spring05 SpringIOC & DI
6 0
|
4天前
|
JavaScript Java 开发者
Spring Boot中的@Lazy注解:概念及实战应用
【4月更文挑战第7天】在Spring Framework中,@Lazy注解是一个非常有用的特性,它允许开发者控制Spring容器的bean初始化时机。本文将详细介绍@Lazy注解的概念,并通过一个实际的例子展示如何在Spring Boot应用中使用它。
17 2
|
6天前
|
前端开发 Java
SpringBoot之自定义注解参数校验
SpringBoot之自定义注解参数校验
16 2
|
12天前
|
安全 Java 开发者
在Spring框架中,IoC和AOP是如何实现的?
【4月更文挑战第30天】在Spring框架中,IoC和AOP是如何实现的?
22 0
|
12天前
|
XML Java 程序员
什么是Spring的IoC容器?
【4月更文挑战第30天】什么是Spring的IoC容器?
20 0
|
12天前
|
Java Spring
springboot自带的@Scheduled注解开启定时任务
springboot自带的@Scheduled注解开启定时任务
|
14天前
|
Java Spring 容器
【Spring系列笔记】IOC与DI
IoC 和 DI 是面向对象编程中的两个相关概念,它们主要用于解决程序中的依赖管理和解耦问题。 控制反转是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入和依赖查找。
32 2