Spring基础:依赖注入(DI)

一. Spring的概述

Spring是Java生态中最为成功的框架,他的核心思想是控制反转(Inverse of Control)和面向切面编程(Aspect Oriented Programming)。Spring的优势:

  • Spring可以通过配置(XML或注解)来扩展POJO的功能,通过依赖注入实现系统解耦
  • 使用AOP技术消除了系统中事务的try…catch…finally模板代码,通过声明式事务技术使得开发人员可以专注于业务逻辑
  • Spring提供了很对模板类来整合其他优秀的开源框架,统一模板简化开发,例如HibernateTemplate,RedisTemplate等

控制反转(IoC) 的核心思想就是将程序中对象创建的主动权由程序本身转为交由第三方创建(IoC容器)! 例如程序中的Controller,Service,Repository以及各种第三方框架的组件(@Component / @Bean)的初始化交由Spring的IoC容器,开发人员只需要通过描述的方式(XML or 注解)将这些组件注册到spring容器中即可。Spring容器在初始化的时候会创建容器中注册的组件,并且通过解析组件的依赖关系(@Autowired)完成依赖对象的注入。所以当程序从容器中获取指定组件的时候,容器确保组件已经完成初始化,并且已经注入所依赖的组件,达到开箱即用。

二. 在Spring IoC 容器中装配Bean

1. 2种依赖注入的方式

Spring中依赖注入主要分为:构造方法注入和属性注入。构造方法注入 需要在Bean中提供有参的构造方法,组件通过参数注入。

public class UserController {
    
    private UserService userService;
    
    public UserService getUserService() {
        return userService;
    }

    // 属性的setter方法
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
    
    // 无参构造器
    public UserController(){}

    // 通过构造方法的参数注入组件对象
    public UserController(UserService userService){
        this.userService = userService;
    }
}

在applicationContext.xml配置文件中为UserController组件注入UserService对象:

<?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">

    <!-- 通过XML完成组件的注册 -->
    <bean id="userController" class="com.znker.controller.UserController">
        <!-- 通过构造方法完成对象的注入,ref标签通过id引用容器中的Bean -->
        <constructor-arg index="0" ref="userService"/>
    </bean>

    <bean id="userService" class="com.znker.service.UserService" />

</beans>

这是比较原始的注入方法,constructor-arg元素用于定义类构造方法的参数,index指定入参顺序,value引用为属性注入的值。

属性注入 是通过属性对应的setter方法注入。

<?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">

    <!-- 通过XML完成组件的注册 -->
    <bean id="userController" class="com.znker.controller.UserController">
        <!-- 使用setter方法注入,因为使用反射技术,Bean需要提供一个无参构造器
             property元素:指定需要注入的属性
             value元素:引用容器中Bean对象完成注入,根据Bean名称注入
         -->
        <property name="userService" ref="userService"/>
    </bean>

    <bean id="userService" class="com.znker.service.UserService" />

</beans>

2. 装配容器中的Bean

Spring将自己开发的Bean和第三方类库Bean注册到容器中主要有三种方法:

  • 在XML文件显式配置(主要是第三方类库,例如DataSource,RedisTempalte…)
  • 使用注解,Bean的扫描和注册以及自动装配机制(@Bean / @Component,@Autowired)
  • 使用java配置类注册Bean

使用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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
        <!-- 向Bean中显式注入简单值 -->
        <property name="username" value="root"/>
        <property name="password" value="1234"/>
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/demo"/>
    </bean>

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 为属性注入容器中的Bean对象 -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 注入简单值 -->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>

    <!-- 扫描Mapper接口,将通过动态代理生成的Bean注册到容器中去 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 注入简单值,指明扫描的包 -->
        <property name="basePackage" value="com.znker.mapper"/>
        <!-- 注入简单值,从容器中寻找id为sqlSessionFactory的Bean注入 -->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        <!-- 扫描所有带有@Repository注解的代理类,将其作为Bean注册到容器中去 -->
        <property name="annotationClass" value="org.springframework.stereotype.Repository"/>
    </bean>
    
</beans>

除了注入简单值和引用对象之外,还能给Bean注入集合和映射对象。

Spring中的那些注解:

除了XML外还可以使用注解装配Bean,并且注解更加流行(springboot推荐全注解)。注解开发提供了自动装配的功能。使用注解开发需要解决两个问题:1. 让spring发现并注册Bean到容器中(注解扫描),2. 完成容器中Bean依赖关系的自动装配(依赖注入)。

注解@Component告知Spring将这个类扫描生成为Bean注册到容器中,value元素表示该Bean在容器中的id,默认是类首字母的小写。

@Component	// Spring扫描到该类的时候会将它注册为容器中的Bean
public class UserService {

    @Autowired
    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public UserDao getUserDao() {
        return userDao;
    }
}

@Component注解还有三个派生注解:@Controller@ServiceRepository这三个注解和也可能将pojo标识为容器中的Bean,在分层开发的的结构中,这些注解会使得pojo的作用更加清晰。

除了给pojo加注解之外,还要告知spring去哪里扫描对应的pojo,在使用java配置类开发的时候,可以使用@ComponentScan注解标识需要扫描的包

package com.znker.dao;

import org.springframework.context.annotation.ComponentScan;
// 该注解告知spring扫描指定包及其子包下所有的类,将带有@Component注解的pojo注册为容器中的Bean
// 如果该注解不指定basePackages元素,默认扫描当前配置类所在的包,basePackages可以指定多个包
@ComponentScan(basePackages = {"com.znker.dao"})
public class DaoConfig {

}

注解@Autowired实现了容器中Bean之间依赖关系的自动装配。Spring容器在初始化的时候完成容器中的Bean的定义和生成,然后寻找Bean所需的资源,完成依赖注入。@Autowired注解默认是按容器中Bean的类型完成依赖项查找和注入的(byType)

@Controller
public class UserController {
	// 从容器中查找UserService类型的Bean注入
    @Autowired
    private UserService userService;

}

按类型注入可能会存在Bean不唯一的情况,例如容器有多个UserService接口的实现类,此时spring不知道该注入哪个实现类,需要其它辅助方法来消除歧义。@Primary注解标注在其中某个实现类上,告知当出现歧义的时候,优先使用该Bean注入,而@Qualifier标注在需要注入资源属性上,此时按照容器中Bean的id来注入所需资源(默认是实现类的类名的首字母小写),从而消除歧义。

注解@Bean@Component一样都可以标注pojo为容器中的Bean,但是@Bean有一个特殊的用法,它可以将方法返回的对象作为Bean存放到容器中。

实际开发中,XML和注解是混合使用的,一般项目中自己开发的pojo优先使用注解配置(Controller,Service,Repository…),而第三方组件(DataSource,RedisTemplate…)则用XML配置更加方便。如果是基于java配置的项目中,使用@ImportResource可以导入XML配置文件,将XML中定义的Bean注册到spring容器中去。

package com.znker.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ImportResource;

// 该注解导入了xml配置文件中定义的Bean,配置项是个数组,可用引入多个xml配置文件,用逗号隔开
@ImportResource({"classpath:spring-dao.xml"})
@ComponentScan("com.znker.*")
public class ApplicationConfig {

}

在分模块开发的时候,项目中可能有多个XML配置文件,此时可以在主配置文件中导入各个模块的配置文件。此时主配置文件中就有所有Bean的注册信息,容器使用主配置文件初始化的时候就能注册工程中的所有Bean

<import resource="classpath:spring-dao.xml"/>

在基于xml配置文件初始化容器的时候,需要指定容器需要扫描的包,将标有注解的pojo注册为容器中的Bean:

<!-- 扫描指定包极其子包下所有类,将标注了@Component、@Bean等注解的pojo注册为容器中的Bean -->
<context:component-scan base-package="com.znker.*"/>

加载属性文件:

开发过程中属性配置经常写到properties属性文件中,这样更改属性的时就无需修改项目源代码了,方便环境切换。注解@PropertySource用于将属性配置文件引入java配置类中。database.properties属性文件:

jdbc.database.driver=com.mysql.jdbc.Driver
jdbc.database.url=jdbc:mysql://localhost:3306/demo
jdbc.database.username=root
jdbc.database.password=1234
// 加载属性文件
@PropertySource(value = {"classpath:database.properties"})
public class ApplicationConfig {

}

使用xml的方式加载属性文件:

<!-- 加载属性文件,多个属性文件之间使用逗号隔开 -->
<conontext:property-placeholder location="classpath:database.properties"/>

注解@Value和占位符可以引用属性文件中的配置@Value("${jdbc.database.driver}")将属性值注入到pojo的属性中。

Bean的作用域:

在默认情况下,spring容器的Bean只有一个实例

  • 单例(singleton):默认选项,整个应用只生成一个实例,容器中组件共用一个实例
  • 原型(prototype):多例模式,每次注入或者从容器中获取Bean实例的时候spring容器都会创建一个新的实例
  • 会话(session):在web应用中,在一个会话过程中只创建一个实例
  • 请求(request):在web应用中,在一个请求过程中会创建一个实例
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值