【Spring系列】自动注入(装配)

简介: 我们把 Spring 在 Bean 与 Bean 之间建立依赖关系的行为称为“装配”。Spring 的 IOC 容器虽然功能强大,但它本身不过只是一个空壳而已,它自己并不能独自完成装配工作。需要我们主动将 Bean 放进去,并告诉它 Bean 和 Bean 之间的依赖关系,它才能按照我们的要求完成装配工作。在前面的学习中,我们都是在 XML 配置中通过 和 中的 ref 属性,手动维护 Bean 与 Bean 之间的依赖关系的。对于只包含少量 Bean 的应用来说,这种方式已经足够满足我们的需求了。但随着应用的不断发展,容器中包含的 Bean 会越来越多,Bean 和 Bean 之

Spring 自动装配(基于xml配置文件)


Spring 的自动装配功能可以让 Spring 容器依据某种规则(自动装配的规则,有五种),为指定的 Bean 从应用的上下文(AppplicationContext 容器)中查找它所依赖的 Bean,并自动建立 Bean 之间的依赖关系。而这一过程是在完全不使用任何 和 元素 ref 属性的情况下进行的。


Spring 的自动装配功能能够有效地简化 Spring 应用的 XML 配置,因此在配置数量相当多时采用自动装配降低工作量。


Spring 框架式默认不支持自动装配的,要想使用自动装配,则需要对 Spring XML 配置文件中 元素的 autowire 属性进行设置


Spring 共提供了 5 中自动装配规则,它们分别与 autowire 属性的 5 个取值对应


a8ffc912765d484982fe3b58c50d862f (1).png


不使用自动装配(autowire=“no”)



autowire=“no” 表示不使用自动装配,此时我们必须通过 <bean> 元素的 <constructor-arg>和 <property> 元素的 ref 属性维护 Bean 的依赖关系

Dept部门类


public class Dept {
    private Integer id;
    private String name;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Dept{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}


Employee员工类


public class Employee {
    private Integer E_id;
    private String name;
    private Dept dept;
    public Integer getE_id() {
        return E_id;
    }
    public void setE_id(Integer e_id) {
        E_id = e_id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Dept getDept() {
        return dept;
    }
    public void setDept(Dept dept) {
        this.dept = dept;
    }
    @Override
    public String toString() {
        return "Employee{" +
                "E_id=" + E_id +
                ", name='" + name + '\'' +
                ", dept=" + dept +
                '}';
    }
}


autowire="no"


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--管理DEPT-->
    <bean id="dept" class="com.liu.pojo.Dept">
        <property name="id" value="1"/>
        <property name="name" value="技术部"/>
    </bean>
    <!--管理员工-->
    <bean id="employee" class="com.liu.pojo.Employee" autowire="no">
        <property name="e_id" value="1"/>
        <property name="name" value="李白"/>
        <property name="dept" ref="dept"/>
    </bean>
</beans>


Test


public class AutoDITest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        Employee employee = context.getBean("employee", Employee.class);
        System.out.println(employee);
    }
}


结果


Employee{E_id=1, name='李白', dept=Dept{id=1, name='技术部'}}
1


按名称自动装配(autowire=“byName”)



autowire=“byName” 表示按属性名称自动装配,XML 文件中 Bean 的 id 或 name 必须与类中的属性名称相同。


<!--管理DEPT-->
<bean id="dept" class="com.liu.pojo.Dept">
    <property name="id" value="1"/>
    <property name="name" value="技术部"/>
</bean>
<!--管理员工-->
<bean id="employee" class="com.liu.pojo.Employee" autowire="byName">
    <property name="e_id" value="1"/>
    <property name="name" value="李白"/>
</bean>
Employee{E_id=1, name='李白', dept=Dept{id=1, name='技术部'}}


如果名字不一样,比如改下dept的id,则就会注入不成功,部门为null


<!--管理DEPT-->
<bean id="dept1" class="com.liu.pojo.Dept">
    <property name="id" value="1"/>
    <property name="name" value="技术部"/>
</bean>
<!--管理员工-->
<bean id="employee" class="com.liu.pojo.Employee" autowire="byName">
    <property name="e_id" value="1"/>
    <property name="name" value="李白"/>
</bean>
Employee{E_id=1, name='李白', dept=null}


按类型自动装配(autowire=“byType”)



autowire=“byType” 表示按类中对象属性数据类型进行自动装配。即使 XML 文件中 Bean 的 id 或 name 与类中的属性名不同,只要 Bean 的 class 属性值与类中的对象属性的类型相同,就可以完成自动装配。


<!--管理DEPT-->
<bean id="dept1" class="com.liu.pojo.Dept">
    <property name="id" value="1"/>
    <property name="name" value="技术部"/>
</bean>
<!--管理员工-->
<bean id="employee" class="com.liu.pojo.Employee" autowire="byType">
    <property name="e_id" value="1"/>
    <property name="name" value="李白"/>
</bean>


现在虽然id不一样了,但是是按照类型进行注入的,需要com.liu.pojo.Dept类型的,去spring工厂里找,咦,找到了,就把找到这个bean注入给需要的bean,如果没找到,就无法注入

Employee{E_id=1, name='李白', dept=Dept{id=1, name='技术部'}}


如果同时存在多个相同类型的 Bean,则注入失败,并且引发异常。


IDEA还是很智能的,直接提示了,并且这样运行也会报错,因为spring也蒙蔽了,他也不知道要注入哪个bean了,他解决不了这个问题,就报错了


ac64ce9c181b482ebab9514e07b5ddbc (1).png


构造函数自动装配(autowire=“constructor”)


autowire=“constructor” 表示按照 Java 类中构造函数进行自动装配。


<!--管理DEPT-->
<bean id="dept1" class="com.liu.pojo.Dept">
    <constructor-arg name="id" value="1"/>
    <constructor-arg name="name" value="技术部"/>
</bean>
<!--管理员工-->
<bean id="employee" class="com.liu.pojo.Employee" autowire="constructor">
    <constructor-arg index="0" value="1"/>
    <constructor-arg index="1" value="李白"/>
</bean>
Employee{E_id=1, name='李白', dept=Dept{id=1, name='技术部'}}


默认的自动装配模式(autowire=“default”)


<!--管理DEPT-->
<bean id="dept1" class="com.liu.pojo.Dept">
    <property name="id" value="1"/>
    <property name="name" value="技术部"/>
</bean>
<!--管理员工-->
<bean id="employee" class="com.liu.pojo.Employee" autowire="default">
    <property name="e_id" value="1"/>
    <property name="name" value="李白"/>
</bean>
Employee{E_id=1, name='李白', dept=Dept{id=1, name='技术部'}}


Spring自动装配 (基于注解)


从 Java 5 开始,Java 增加了对注解(Annotation)的支持,它是代码中的一种特殊标记,可以在编译、类加载和运行时被读取,执行相应的处理。开发人员可以通过注解在不改变原有代码和逻辑的情况下,在源代码中嵌入补充信息。


Spring 从 2.5 版本开始提供了对注解技术的全面支持,我们可以使用注解来实现自动装配,简化 Spring 的 XML 配置。


Spring 通过注解实现自动装配的步骤如下:


引入依赖

开启组件扫描

使用注解定义 Bean

依赖注入


1. 引入AOP依赖


使用注解的第一步,就是要在项目中引入以下 Jar 包。

org.springframework.core-5.3.13.jar

org.springframework.beans-5.3.13.jar

spring-context-5.3.13.jar

spring-expression-5.3.13.jar

commons.logging-1.2.jar

spring-aop-5.3.13.jar


maven项目直接导入以下依赖坐标即可


<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>4.3.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>4.3.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>4.3.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-expression</artifactId>
    <version>4.3.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>4.3.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>4.3.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.3.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>4.3.2.RELEASE</version>
</dependency>


2. 开启组件扫描


Spring 默认不使用注解装配 Bean,因此我们需要在 Spring 的 XML 配置中,通过 <context:component-scan> 元素开启 Spring Beans的自动扫描功能。开启此功能后,Spring 会自动从扫描指定的包(base-package 属性设置)及其子包下的所有类,如果类上使用了 @Component 注解,就将该类装配到容器中。


<?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">
    <!--xmlns:context="http://www.springframework.org/schema/context" 注意别导错了-->
    <!--开启组件扫描功能 扫描com.liu包下所有类是否添加了@Component注解-->
    <context:component-scan base-package="com.liu"/>
</beans>


注意:在使用 context:component-scan 元素开启自动扫描功能前,首先需要在 XML 配置的一级标签 中添加 context 相关的约束


3. 使用注解定义 Bean


Spring 提供了以下多个注解,这些注解可以直接标注在 Java 类上,将它们定义成 Spring Bean。


bfc4d1b70bca4ea79780d47d69f4fb2b.png


4. 基于注解方式实现依赖注入


我们可以通过以下注解将定义好 Bean 装配到其它的 Bean 中。


4a12b444caa44953bc433246926f0f8f.png


1.创建maven工程


2.导入相关依赖在pom.xm配置文件中


<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.3.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>4.3.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.3.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>4.3.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.3.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
        <version>4.3.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>4.3.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>4.3.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>4.3.2.RELEASE</version>
    </dependency>
    <!--springmvc核心依赖-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>4.3.2.RELEASE</version>
    </dependency>
    <!--servlet-api-->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
        <scope>provided</scope>
    </dependency>
    <!--jstl-->
    <dependency>
        <groupId>jstl</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
    <!--mybatis-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.5</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>1.3.3</version>
    </dependency>
    <!--mysql-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
    <!--log4j-->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.17.1</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.25</version>
    </dependency>
    <!--fastjson-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.62</version>
    </dependency>
    <!--druid-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.8</version>
    </dependency>
</dependencies>


3.在 com.liu.dao 包下,创建一个名为 UserDAO 的接口


85cf5fd12f104aa8aff9d78f477f7558.png

public interface UserDAO {
    void print();
}


4.在com.liu.dao.impl 包下,创建 UserDao 的实现类 UserDAOImpl


8dae13d1d3b94f01b89c07e175fe350d.png

/*注解 @Repository 将这个dao层类交给spring容器管理
* 尽管我们并没有在spring.xml中进行相应配置,这里的字符串
* value就相当于spring.xml配置bean时的id属性,底层反射代理*/
@Repository(value = "userDAO")
public class UserDAOImpl implements UserDAO {
    @Override
    public void print() {
        System.out.println("hello auto");
    }
}


5.在 com.liu.service 包下,创建一个名为 UserService 的接口


953d051c99ab40a0b95dc7f1e5712ae5.png

public interface UserService {
    void out();
}


6.在 com.liu.service.impl 包下,创建 UserService 的实现类 UserServiceImpl


/*这里@Service注解用于标识他是业务层类,然后
* 添加此注解,它就会被spring容器所管理,value
* 属性还是同理*/
@Service(value = "userService")
public class UserServiceImpl implements UserService {
    /*这里的@Resource注解是用于依赖注入的,以前我们就是通过配置
    * 现在直接在需要的地方,添加相应注解,就实现对他的注入,简化了
    * 配置文件的大小以及开发的繁琐,@Resource默认是按照类型进行注入的,
    * 你也可以指定它的name属性,让他按照name进行注入,或者指定name和
    * type这时,他会先按照name进行找,找不到在按照type进行查找,还找不到
    * 就会报错了*/
    @Resource
    private UserDAO userDAO;
    public UserDAO getUserDAO() {
        return userDAO;
    }
    public void setUserDAO(UserDAO userDAO) {
        this.userDAO = userDAO;
    }
    @Override
    public void out() {
        userDAO.print();
        System.out.println("我来了");
    }
}


7. 在 com.liu.controller 包下,创建一个名为 UserController 的类


ec6043a07c6548308e0bd8315480a911.png

什么时候给value呢,如果他被其他类需要,或者需要被main调用,就需要给value,就相当于我们在配置文件中给他了一个唯一标识id,然后工厂可以根据id拿到该bean,因为接下来要实例化它,所以给他添加了一个value属性


@Controller("userController")
public class UserController {
    @Resource
    private UserService userService;
    public UserService getUserService() {
        return userService;
    }
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
    public void doStr(){
        userService.out();
    }
}


8.创建 Spring 配置文件 Beans.xml,配置内容如下


注意:xml的相应依赖要导入全,不然会报错的,很好解决


<?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-3.0.xsd
                          http://www.springframework.org/schema/context
                          http://www.springframework.org/schema/context/spring-context.xsd">
    <!--xmlns:context="http://www.springframework.org/schema/context" 注意别导错了-->
    <!--开启组件扫描功能 扫描com.liu包下所有类是否添加了@Component注解-->
    <context:component-scan base-package="com.liu"></context:component-scan>
</beans>


9.测试


前端来一个请求,被springmvc拦截,交给了controller,然后controller被spring创建管理,controller的方法调用 service 层,service等去调用 dao 层,完成业务逻辑的处理,返回结果,然而spring为我们做了太多,对象的创建管理,虽然我们没有配置文件xml,但是我们通过注解的方式,注解传入了重要的信息,注解其实就是通过反射去创建对象,单例多例可以看设计模式,还有工厂模式,代理,动态代理,一下子全穿起来吧,是不是觉得豁然开朗,多学,重复写,这种领悟会越来越深刻,越来越清晰,就是在这种状态下进步的,ok


public class Test {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        UserController userController = context.getBean("userController", UserController.class);
        userController.doStr();
    }
}


输出

hello auto
我来了


相关文章
|
2月前
|
XML Java 程序员
Spring6框架中依赖注入的多种方式(推荐构造器注入)
依赖注入(DI)是一种过程,对象通过构造函数参数、工厂方法的参数或在对象实例构建后设置的属性来定义它们的依赖关系(即与其一起工作的其他对象)。
40 3
|
4天前
|
Java Spring 容器
spring如何进行依赖注入,通过set方法把Dao注入到serves
spring如何进行依赖注入,通过set方法把Dao注入到serves
|
12天前
|
Java Spring 容器
在 Spring Boot 中,条件装配(Conditional Configuration)和条件注解(Conditional Annotations)
在 Spring Boot 中,条件装配(Conditional Configuration)和条件注解(Conditional Annotations)
14 1
|
20天前
|
Java Spring
解决 Spring 中 Prototype Bean 注入后被固定的问题
【6月更文挑战第8天】学习 Spring 框架内不原理的意义就是,当遇到问题时,分析出原因,就可以从多个切入点,利用 Spring 的特性,来解决问题。
32 2
|
27天前
spring-boot报错循环注入报错:has been injected into other beans
spring-boot报错循环注入报错:has been injected into other beans
68 3
|
5天前
|
Java Linux 程序员
技术笔记:Spring生态研习【五】:Springboot中bean的条件注入
技术笔记:Spring生态研习【五】:Springboot中bean的条件注入
|
16天前
|
SQL 安全 Java
Spring Boot中的跨站点脚本攻击(XSS)与SQL注入防护
【6月更文挑战第15天】在现代Web应用程序开发中,安全性是一个至关重要的课题。跨站点脚本攻击(XSS)和SQL注入是最常见的两种攻击类型,它们可以严重威胁到应用程序的安全。
75 0
|
2月前
|
前端开发 Java 编译器
详解Spring与JDK注入
依赖注入是Spring框架的核心概念之一,它通过将对象之间的依赖关系外部化,实现了松耦合和可测试性。面向切面编程则允许开发人员将横切关注点(如日志、事务管理)从应用程序的主要业务逻辑中分离出来,以提高代码的模块化和可维护性。
27 4
|
2月前
|
XML Java 数据格式
Spring 属性注入方式
Spring 属性注入方式
22 2
|
2月前
|
Java Spring 容器
Spring注入
Spring注入
38 13