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创建和管理的)。

相关文章
|
2月前
|
缓存 监控 Java
SpringBoot @Scheduled 注解详解
使用`@Scheduled`注解实现方法周期性执行,支持固定间隔、延迟或Cron表达式触发,基于Spring Task,适用于日志清理、数据同步等定时任务场景。需启用`@EnableScheduling`,注意线程阻塞与分布式重复问题,推荐结合`@Async`异步处理,提升任务调度效率。
513 128
|
2月前
|
XML 安全 Java
使用 Spring 的 @Aspect 和 @Pointcut 注解简化面向方面的编程 (AOP)
面向方面编程(AOP)通过分离横切关注点,如日志、安全和事务,提升代码模块化与可维护性。Spring 提供了对 AOP 的强大支持,核心注解 `@Aspect` 和 `@Pointcut` 使得定义切面与切入点变得简洁直观。`@Aspect` 标记切面类,集中处理通用逻辑;`@Pointcut` 则通过表达式定义通知的应用位置,提高代码可读性与复用性。二者结合,使开发者能清晰划分业务逻辑与辅助功能,简化维护并提升系统灵活性。Spring AOP 借助代理机制实现运行时织入,与 Spring 容器无缝集成,支持依赖注入与声明式配置,是构建清晰、高内聚应用的理想选择。
406 0
|
1月前
|
XML Java 测试技术
《深入理解Spring》:IoC容器核心原理与实战
Spring IoC通过控制反转与依赖注入实现对象间的解耦,由容器统一管理Bean的生命周期与依赖关系。支持XML、注解和Java配置三种方式,结合作用域、条件化配置与循环依赖处理等机制,提升应用的可维护性与可测试性,是现代Java开发的核心基石。
|
1月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
354 2
|
2月前
|
XML Java 数据格式
常用SpringBoot注解汇总与用法说明
这些注解的使用和组合是Spring Boot快速开发和微服务实现的基础,通过它们,可以有效地指导Spring容器进行类发现、自动装配、配置、代理和管理等核心功能。开发者应当根据项目实际需求,运用这些注解来优化代码结构和服务逻辑。
288 12
|
2月前
|
Java 测试技术 数据库
使用Spring的@Retryable注解进行自动重试
在现代软件开发中,容错性和弹性至关重要。Spring框架提供的`@Retryable`注解为处理瞬时故障提供了一种声明式、可配置的重试机制,使开发者能够以简洁的方式增强应用的自我恢复能力。本文深入解析了`@Retryable`的使用方法及其参数配置,并结合`@Recover`实现失败回退策略,帮助构建更健壮、可靠的应用程序。
333 1
使用Spring的@Retryable注解进行自动重试
|
2月前
|
传感器 Java 数据库
探索Spring Boot的@Conditional注解的上下文配置
Spring Boot 的 `@Conditional` 注解可根据不同条件动态控制 Bean 的加载,提升应用的灵活性与可配置性。本文深入解析其用法与优势,并结合实例展示如何通过自定义条件类实现环境适配的智能配置。
179 0
探索Spring Boot的@Conditional注解的上下文配置
|
2月前
|
智能设计 Java 测试技术
Spring中最大化@Lazy注解,实现资源高效利用
本文深入探讨了 Spring 框架中的 `@Lazy` 注解,介绍了其在资源管理和性能优化中的作用。通过延迟初始化 Bean,`@Lazy` 可显著提升应用启动速度,合理利用系统资源,并增强对 Bean 生命周期的控制。文章还分析了 `@Lazy` 的工作机制、使用场景、最佳实践以及常见陷阱与解决方案,帮助开发者更高效地构建可扩展、高性能的 Spring 应用程序。
129 0
Spring中最大化@Lazy注解,实现资源高效利用
|
2月前
|
安全 IDE Java
Spring 的@FieldDefaults和@Data:Lombok 注解以实现更简洁的代码
本文介绍了如何在 Spring 应用程序中使用 Project Lombok 的 `@Data` 和 `@FieldDefaults` 注解来减少样板代码,提升代码可读性和可维护性,并探讨了其适用场景与限制。
134 0
Spring 的@FieldDefaults和@Data:Lombok 注解以实现更简洁的代码
|
2月前
|
Java 测试技术 编译器
@GrpcService使用注解在 Spring Boot 中开始使用 gRPC
本文介绍了如何在Spring Boot应用中集成gRPC框架,使用`@GrpcService`注解实现高效、可扩展的服务间通信。内容涵盖gRPC与Protocol Buffers的原理、环境配置、服务定义与实现、测试方法等,帮助开发者快速构建高性能的微服务系统。
537 0

热门文章

最新文章

下一篇
oss云网关配置