Spring中的依赖注入

IOC的作用:
降低程序间的耦合(依赖关系)
依赖关系的管理:
以后都交给spring来维护,在当前类需要用到其他类的对象,由spring为我们提供,我们只需要在配置文件中说明依赖关系的维护,就称之为依赖注入。
依赖注入:
能注入的数据有三类:

  • 基本类型和String
  • 其他bean类型( 在配置文件中或者注解配置过的bean)
  • 复杂类型/集合类型

注入的方式有三种:

  • 使用构造函数提供
  • 使用set方法提供
  • 第三种:使用注解提供

注入方式

1.构造函数往入:

使用的标签:constructor-arg
标签出现的位置:bean标签的内部
标签中的属性

  • type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型。
  • index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值。索引的位置是从0开始。
  • name:用于指定给构造函数中指定名称的参数赋值。(常用的)
    以上三个用于指定给构造函数中哪个参数赋值
  • value:用于提供基本类型和String类型的数据。
  • ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象。

优势:在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功。
弊端:改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供。

例:

<bean id="student" class="com.Student"><constructor-arg name="name" value="小泓"/><constructor-arg name="sex" value="女"/><constructor-arg name="birthday" ref="now"/>
</bean>
<!--配置一个日期对象-->
<bean id="now" class="java.util.Date"/>
import java.util.Date;public class Student {private String name;private String sex;private Date birthday;public Student(String name, String sex, Date birthday) {this.name = name;this.sex = sex;this.birthday = birthday;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", sex='" + sex + '\'' +", birthday=" + birthday +'}';}
}
    @Testpublic void demo(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");Student student = applicationContext.getBean(Student.class);System.out.println(student.toString());}

结果:

2.Set方法注入

涉及的标签:property
出现的位置:bean标签的内部
标签的属性

  • name:用于指定注入时所调用的set方法名称。
  • value:用于提供基本类型和String类型的数据。
  • ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象。

优势:创建对象时没有明确的限制,可以直接使用默认构造函数。
弊端:如果有某个成员必须有值,则获取对象是有可能set方法没有执行。

例:

    <bean id="now" class="java.util.Date"/><bean id="student2" class="com.Student2"><property name="name" value="小欢"/><property name="sex" value="男"/><property name="birthday" ref="now"/></bean>

注意:property标签里面name属性的名称取决于对应实体类中set方法的名称。

实体类

import java.util.Date;public class Student2 {private String name;private String sex;private Date birthday;public void setName(String name) {this.name = name;}public void setSex(String sex) {this.sex = sex;}public void setBirthday(Date birthday) {this.birthday = birthday;}@Overridepublic String toString() {return "Student2{" +"name='" + name + '\'' +", sex='" + sex + '\'' +", birthday=" + birthday +'}';}
}

测试类

    @Testpublic void demo2(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");Student2 student2 = applicationContext.getBean(Student2.class);System.out.println(student2.toString());}

复杂类型的注入

用于给List结构集合往入的标签:list、array、set
用于个Map结构集合注入的标签:map、props
注意:结构相同,标签可以互换。

<!--复杂类型的注入/集合类型的注入--><bean id="source" class="com.Source"><!--数组类型--><property name="myStrs"><array><value>AAA</value><value>BBB</value><value>CCC</value></array></property><!--集合类型--><property name="myList"><list><value>aaa</value><value>bbb</value><value>ccc</value></list></property><!--Set集合类型--><property name="mySet"><set><value>111</value><value>222</value><value>333</value></set></property><!--Map类型--><property name="myMap"><map><entry key="testA" value="aaa"/><entry key="testB"><value>bbb</value></entry></map></property><!--Properties类型--><property name="myProps"><props><prop key="testA">111</prop><prop key="testB">222</prop></props></property></bean>

实体类

import java.util.*;public class Source {private String[] myStrs;private List<String> myList;private Set<String> mySet;private Map<String,String> myMap;private Properties myProps;public void setMyStrs(String[] myStrs) {this.myStrs = myStrs;}public void setMyList(List<String> myList) {this.myList = myList;}public void setMySet(Set<String> mySet) {this.mySet = mySet;}public void setMyMap(Map<String, String> myMap) {this.myMap = myMap;}public void setMyProps(Properties myProps) {this.myProps = myProps;}public void save(){System.out.println(Arrays.toString(myStrs));System.out.println(myList);System.out.println(myMap);System.out.println(mySet);System.out.println(myProps);}
}

测试类

    @Testpublic void demo3(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");Source source = applicationContext.getBean(Source.class);source.save();}

结果:

3.自动装配

常用的IOC注解

曾经的xml的配置:

<bean id="" class="" scope="" init-method="" destroy-method=""><property name="" value=""/ref=""></property>
</bean>

配置文件的改动

<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--告知spring在创建容器时要扫描的包,配置所需要的标签不是在beans的约束中,而是一个名称为context名称空间和约束中--><!-- 配置注解bean所在的包 --><!--自动扫描--> <!--base-package放的是包名,有多个包名中间用逗号隔开--><context:component-scan base-package="com"/>
</beans>
3.1 用于创建对象的注释

他们的作用就和在XML配置文件中编写个< bean >标签实现的功能是样的。

@Component :

作用:
用于把当前类对象存入spring容器中。
属性:
value:用于指定bean的id。当我们不写时,它的默认值是当前类名,且首字母改小写。

例:

实体类

import org.springframework.stereotype.Component;@Component(value = "username")   //这里的value可以不写,不写的话默认id为当前类名的首字母小写
//相当于xml文件中配置<bean id="" class=""/> class就是当前类
public class User {public void save(){System.out.println("对象创建了");}
}

测试类

    @Testpublic void demo1(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");User user = (User) applicationContext.getBean("username");user.save();}

结果:

@Controller、@Service和@Repository

Controller:一般用在表现层
Service:一般用在业务层
Repository:般用在持久层
以上三个注解他们的作用和属性与Component是一模一样。
他们三个是spring框架为我们提供明确的三层使用的注解,使我们的三层对象更加清晰。

3.2 用于注入数据的注释

他们的作用就和在 xmL配置文件中的bean标签中写一个< property >标签的作用是一样的。

@Autowired

作用:
自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功。如果ioc容器中没有任何bean的类型和要注入的变量类型匹配,则报错。
出现位置:
可以是变量上,也可以是方法上
细节:
在使用注解注入时,set方法就不是必须的了。

例:
我们重新创建过一个项目,使用三层架构的模式
Dao层实体类

import com.dao.UserDao;
import org.springframework.stereotype.Repository;@Repository(value = "userDao")
public class UserDaoImpl implements UserDao {@Overridepublic void save(){System.out.println("保存数据");}
}

Dao接口

public interface UserDao {void save();
}

Service层实体类

import com.dao.UserDao;
import com.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service(value = "userService")
public class UserServiceImpl implements UserService {@Autowiredprivate UserDao userDao;public UserServiceImpl(){System.out.println("对象创建了");}@Overridepublic void save() {userDao.save();}
}

Service层接口

public interface UserService {void save();
}

测试类

    @Testpublic void demo2(){//1.获取核心容器对象ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");//2.根据id获取Bean对象UserService userService  = applicationContext.getBean("userService",UserService.class);userService.save();}

运行结果:

我们可以看到,运行结果出现了空指针异常。

我的理解:
一开始没有写上@Autowired时,userDao没有注入依赖,为空,所以运行测试类时会出现空指针异常;

当写上@Autowired注解后,该注解就会根据userDao变量的数据类型去寻找符合该类型的bean注入进去,这就是自动按照类型装配。

加上@Autowired注解后运行结果:

还有另一种情况,即当出现两个同样的bean对象类型时,例:
我们又创建了一个Dao实体类,其他不变

import com.dao.UserDao;
import org.springframework.stereotype.Repository;@Repository(value = "userDao2")
public class UserDaoImpl2 implements UserDao {@Overridepublic void save() {System.out.println("保存数据222");}
}

运行结果:

这里很明显报错了,大概意思是预期的bean对象类型只应该有一个,但是它却找到两个,即:userDao1和userDao2
我们可以对代码进行一下修改解决这个问题,如下:

@Repository(value = "userDao1")      //修改bean的id
public class UserDaoImpl implements UserDao {@Overridepublic void save(){System.out.println("保存数据111");}
}
import com.dao.UserDao;
import com.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service(value = "userService")
public class UserServiceImpl implements UserService {@Autowiredprivate UserDao userDao1;   //将变量的名字修改public UserServiceImpl(){System.out.println("对象创建了");}@Overridepublic void save() {userDao1.save();}
}

运行结果:

总结:
如果有唯一的一个匹配时,直接注入;
如果有多个匹配时,首先它先按照类型圈定匹配的对象,接下来它会使用变量名称作为bean的id,在已经圈定出来的对象里面继续查找有哪一个是和它一样的,如果一样即查找成功,如果两个都不一样就报错。

@Qualifier

作用:
在按照类中注入的基础之上再按照名称注入。它在给类成员注入时不能单独使用,必须得和@Autowried组合在一起使用。但是在给方法参数往入时可以。
属性:
value:用于指定注入bean的id。

例:

import com.dao.UserDao;
import com.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;@Service(value = "userService")
public class UserServiceImpl implements UserService {@Autowired@Qualifier(value = "userDao1")  //使用了@Qualifier注解后可以指定注入哪个bean对象private UserDao userDao;       //将变量名称修改成和两个bean对象id都不一样public UserServiceImpl(){System.out.println("对象创建了");}@Overridepublic void save() {userDao.save();}
}

结果:

@Resource

作用:
直接按照bean的id注入。它可以独立使用
属性:
name:用于指定bean的id。

例:

@Service(value = "userService")
public class UserServiceImpl implements UserService {@Resource(name = "userDao2")   //直接使用Resource注解指定bean对象idprivate UserDao userDao;public UserServiceImpl(){System.out.println("对象创建了");}@Overridepublic void save() {userDao.save();}
}

结果:

@Value

以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。另外,集合类型的注入只能通过XML来实现。

作用:用于注入基本类型和String类型的数据。
属性:
value:用于指定数据的值。它可以使用spring中SpEL (也就是spring的el表达式) 。SpEL的写法:${表达式}

3.3 用于改变作用范围的注释

他们的作用就和在bean标签中使用scope属性实现的功能是一样的

@Scope

作用:用于指定bean的作用范围
属性:
value:指定范围的取值。常用取值: singleton(单例) prototype(多例) 如果你不写,那它默认情况下也是单例的。
例:

import com.dao.UserDao;
import com.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;@Service(value = "userService")
//我们这里没有使用@Scope注解所以它默认为单例
public class UserServiceImpl implements UserService {@Autowired@Qualifier(value = "userDao1")private UserDao userDao;public UserServiceImpl(){System.out.println("对象创建了");}@Overridepublic void save() {userDao.save();}
}
    @Testpublic void demo3(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");UserService userService1 = applicationContext.getBean("userService",UserService.class);UserService userService2 = applicationContext.getBean("userService",UserService.class);System.out.println(userService1==userService2);}

结果:

例:
修改实体类,测试类不变

import com.dao.UserDao;
import com.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;@Service(value = "userService")
@Scope(value = "prototype")//设置为了多例模式
public class UserServiceImpl implements UserService {@Autowired@Qualifier(value = "userDao1")private UserDao userDao;public UserServiceImpl(){System.out.println("对象创建了");}@Overridepublic void save() {userDao.save();}
}

结果:

我们可以看到,它创建了两次对象,且两个对象不一样。

3.4 和生命周期相关的注释

他们的作用就和在bean标签中使用init-method和destroy-method的作用是一样的

@PostConstruct

作用:用于指定初始化方法

@PreDestroy

作用:用于指定销毁方法

例:

@Service(value = "userService")
public class UserServiceImpl implements UserService {@Autowired@Qualifier(value = "userDao1")private UserDao userDao;public UserServiceImpl(){System.out.println("对象创建了");}@PostConstruct   //初始化方法public void  init(){System.out.println("初始化方法执行了");}@PreDestroy       //销毁方法public void  destroy(){System.out.println("销毁方法执行了");}@Overridepublic void save() {userDao.save();}
}
    @Testpublic void demo4(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");UserService userService = applicationContext.getBean("userService",UserService.class);applicationContext.close();}

结果:

Spring复习笔记:2相关推荐

  1. Spring复习笔记:4

    在复习笔记三中我们进行的案例的编写,我们可以发现,就算使用了注解的方式,xml配置文件文件还是不能够删除,现在我们来将一些新的注解可以让我们去掉xml配置文件. @Configuration 作用:指 ...

  2. Spring复习笔记:3

    Spring基于xml的案例实践 在数据库中创建一张新的表 create table account(id int primary key auto_increment,name varchar(40 ...

  3. Spring复习笔记:1

    ApplicationContext的三个常用实现类: ClassPathXmLApplicationContext: 它可以加载类路径下的配置文件,要求配置文件必须在类路径下.不在类路径的话,加载不 ...

  4. 2021/06/29计算机视觉期末复习笔记整理

    计算机视觉期末复习笔记整理 引言 我的复习参考 期末考试考题回忆 PPT对应中文笔记整理 参考的几篇博客的笔记 引言 刚结束可能是我学生时代最后一场考试了,orz热乎着,记录一下. 这门课是学校新开的 ...

  5. 【Web】javaEE课程复习笔记

    JavaEE复习笔记 根据上课的笔记整理与补充.涵盖web应用开发基础,jsp,标签,注解,struts,spring, mvc, 数据访问等内容 (因为转于个人blog,csdn图片无法显示,可至下 ...

  6. matlab arr3(5 end),matlab复习笔记.doc

    matlab复习笔记.doc 如果一个语句在一行内书写太长了,可能要另起一行接着写,在这种情况下我们需要在第一行末打上半个省略号(),再开始第二行的书写.历史命令窗口(THEHISTORYCOMMAN ...

  7. 【Spring学习笔记-MVC-13.2】Spring MVC之多文件上传

    作者:ssslinppp       1. 摘要 前篇文章讲解了单文件上传<[Spring学习笔记-MVC-13]Spring MVC之文件上传>http://www.cnblogs.co ...

  8. Spring读书笔记——bean创建(下)

    有关Spring加载bean系列,今天这是最后一篇了,主要接上篇对于从Spring容器中获取Bean的一些细节实现的补充. <Spring读书笔记--bean加载>--Spring如何加载 ...

  9. 数据结构(c语言版)笔记6,2020考研计算机《数据结构(C语言版)》复习笔记(6)

    2020年计算机考研复习已经开始,新东方在线在此整理了2020考研计算机<数据结构(C语言版)>复习笔记(6),希望能帮助大家! 第六章 树知识点整理 树是n个结点的有限集合,非空时必须满 ...

最新文章

  1. git服务器搭建问题
  2. 逸仙电商企业网络推广如何打造出百亿完美日记后又收购高端护肤品牌
  3. 技术方案包括哪些内容_揭秘:网络营销推广方案的内容包括哪些?
  4. java 类 加载 初始化_java中类的初始化和加载
  5. python字典值求和_Python两个字典键同值相加的方法总结
  6. qt 保存文件为utf8
  7. Rmarkdown与Rnotebook使用心得
  8. mfc 学习的第二天
  9. Q102:光线追踪场景(4)——面朝大海
  10. 2dpsk调制解调实验matlab_贼详细的8PSK调制与解调详细过程
  11. MongoDB lsm降低 disk lantency
  12. 荐书丨《哥德尔、艾舍尔、巴赫书:集异璧之大成》:机器人与音乐的次元壁破了
  13. dell笔记本怎么开启虚拟化_高颜值轻薄笔记本推荐2020-异形篇
  14. 简述JAVAoop思想
  15. 费马小定理、欧拉定理总结
  16. 【S-CMS企业建站系统 v5.0 】闪灵CMS+含小程序+响应式布局+支持手机版网站+支持QQ旺旺客服
  17. 大揭秘(1):网店背后的隐秘产业链【连载】
  18. 计算机防火墙知识点,防火墙及防火墙的基本概念-信息安全工程师知识点
  19. 阿里云ECS主机部署LAMP环境
  20. 《机器学习算法竞赛实战》整理 | 八、实战案例:Elo Merchant Category Recommendation

热门文章

  1. ATS中的ComboHandler合并回源插件调研
  2. Unity从零开始构建能力体系 Unity Ability System
  3. C++标准库中sstream和strstream的区别
  4. 字符串匹配算法 -- AC自动机 基于Trie树的高效的敏感词过滤算法
  5. 联想拯救者Y9000-ubuntu-U盘启动失败解决方法
  6. Excel导入异常Cannot get a text value from a numeric cell解决
  7. nyoj——297(期望)
  8. sql 优化 tips
  9. session_id
  10. [C#1] 9-委托