Spring复习笔记:2
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();}
结果:
相关文章:

Unity Android 2021:用C#打造3D ZigZag赛车游戏
Unity Android 2021 : Build 3D ZigZag Racing Game with C# MP4 |视频:h264,1280720 |音频:AAC,44.1 KHz,2 Ch 语言:英语中英文字幕(根据原英文字幕机译更准确) |时长:65节课(11h 7m) |大小解压后:3.6 GB …

封装了一套WeCenter的IOS SDK
度过了忙碌且迷茫的2015年,迎来了的郁闷且彷徨的2016年。 与哥们商量做些什么,谈不上创业也不是项目,只是想让2016年不必如2015年一样迷茫,也慰藉一下2016年的彷徨。 方向么,考察了几个行业,也做了些调研&a…

java多线程样例
这里我们做一个完整的样例来说明线程产生的方式不同而生成的线程的差别: package debug;import java.io.*;import java.lang.Thread;class MyThread extends Thread{ public int x 0; public void run(){ System.out.println(x); }}class R implements Runn…

Spring复习笔记:3
Spring基于xml的案例实践 在数据库中创建一张新的表 create table account(id int primary key auto_increment,name varchar(40),money float )character set utf8 collate utf8_general_ci;往表中导入数据 insert into account(name,money) values(aaa,1000); insert into…

Blender多米诺骨牌动画学习教程 The Impossible Domino Run in Blender
流派:电子学习| MP4 |视频:h264,1280720 |音频:AAC,48.0 KHz 语言:英语中英文字幕(根据原英文字幕机译更准确)|大小:8.53 GB 含课程文件 |时长:8h 20m Blender的运动跟踪,建模,渲染和合成工具集…

unity3d游戏开发猜想——当程序猿老去
程序猿将代码注入生命去打造互联网的浪潮之巅。当有一天他们老了。会走向那里,会做些什么?非常多年以后,在我60岁的那天早晨,天刚蒙蒙亮我就起床了,先去公园晨练,然后回来做早餐(50岁的时候我学…

【JavaScript】JavaScript基础-变量、运算符与控制语句
一.变量 变量: 定义一个变量,系统会为之分配一块内存,程序可以用变量名来表示这块内存中的数据。 由于javascript采用的是弱类型的变量形式,因此,在声明一个变量的时候,我们不必声明它的类型,但…

ROW_NUMBER() OVER()函数用法详解 (分组排序 例子多)
ROW_NUMBER() OVER()函数用法详解 (分组排序 例子多) https://blog.csdn.net/qq_25221835/article/details/82762416 posted on 2019-09-05 01:00 竹径风声 阅读(...) 评论(...) 编辑 收藏 转载于:https://www.cnblogs.com/girl1314/p/11462711.html

Blender+Substance Painter全流程制作真实的机器人学习教程
MP4 |视频:h264,1280720 |音频:AAC,44.1 KHz,2 Ch 语言:英语中英文字幕(根据原英文字幕机译更准确) |时长:44节课(10h 52m) |大小解压后:9.9 GB 含课程素材 如何使用Blender 2.8和Substance Painter制作真…

Spring复习笔记:4
在复习笔记三中我们进行的案例的编写,我们可以发现,就算使用了注解的方式,xml配置文件文件还是不能够删除,现在我们来将一些新的注解可以让我们去掉xml配置文件。 Configuration 作用:指定当前类是一个配置类 细节&a…

Extjs PROXY查询params无法传参,改用extraParams
转载于:https://www.cnblogs.com/cocoat/p/5153009.html

详解Paint的setPathEffect(PathEffect effect)
一、setPathEffect() 这个方法一看就和path有关,顾名思义,它就是给path设置样式(效果)的。PathEffect这个路径效果类没有具体的实现,效果是由它的六个子类实现的: 这六个子类分别可以实现不同的路径效果&am…

返回手势导致页面卡死并且UI错乱的问题解决
问题记录:在做了部分页面的转场动画之后,返回手势不灵了,快速连续返回的话会卡住,App退到后台再重新激活之后页面不卡了,但是UI错乱. 解决方案: 1. 在UINavigationController子类实现代理UIGestureRecognizerDelegate,并在viewDidLoad方法中增加代理设置: - (void)viewDidLoad …

Spring学习笔记:3(面向切面AOP)
AOP:Aspect Oriented Program(面向切面) 我们再回顾一下AOP的一些术语: 通知(Advice) 就是你想要的功能,也就是的安全、事物、日志等。先定义好,然后在想用的地方用一下。 连接…

Blender全流程制作真实感3D产品学习教程
MP4 |视频:h264,1280720 |音频:AAC,44.1 KHz,2 Ch 语言:英语中英文字幕(根据原英文字幕机译更准确) |时长:41节课(4h 29m) |大小解压后:4.53 GB 仅使用blender 2.8进行建模、纹理、光照和渲染,…

如何给iOS应用添加原生的二维码扫描功能
之前总觉得二维码扫描很高大上,其实apple工程师早就为我们提供了便捷的方法。二维码扫描第三方的库也挺多的,不过效率高的当属系统提供的扫描方法。 二维码扫描主要用到了以下几个类:AVCaptureDevice,AVCaptureDeviceInput,AVCaptureMetadata…

2021-2027年中国市医疗电子场投资分析及前景预测报告
【报告类型】产业研究 【报告价格】4500起 【出版时间】即时更新(交付时间约3个工作日) 【发布机构】智研瞻产业研究院 【报告格式】PDF版 本报告介绍了中国医疗电子行业市场行业相关概述、中国医疗电子行业市场行业运行环境、分析了中国医疗电子行…

RabbitMQ入门(4)--路由
2019独角兽企业重金招聘Python工程师标准>>> ###路由 ###(使用Java客户端) 在先前的指南中,我们建立了一个简单的日志系统。我们可以将我们的日志信息广播到多个接收者。 在这部分的指南中,我们将要往其中添加一个功能…

从一个数组中寻找出现奇数次的数字
假设给定了数组nums为[0,1,2,3,4,5,6,7,8,9,10,10,9,8,7,6,5,4,1,2,3,3,0] 其中3出现了3次 而其他数字都出现了两次 则我们应该得到结果为3 第一种方式:使用Hash 1 /**2 * 使用hash3 * */4 public static int singleNumber_1(int[] nums) {5 …

Blender写实建筑场景制作学习教程 Exterior Visualization in Blender 2.9
MP4 |视频:h264,1280720 |音频:AAC,44.1 KHz,2 Ch 语言:英语中英文字幕(根据原英文字幕机译更准确) |时长:26节课(3h 41m) |大小:3.3 GB 使用Blender创建惊人的外部渲染。 你会学到: Blender中的建模、着色…

Postman增删改查接口测试
查 一.选择Get方式 二.点击Send开始测试,得出结果 增 一.选择Post方式 二.输入需要增添的数据 三.点击Send测试 四.没有报错,添加成功 查看一下,发现确实添加进去了 删 一.选择Delete方式 二.根据id删除,在请求路径下直接写出…

新安装Ubuntu加载时提示“为/检查磁盘时发生严重错误”的解决方法
本文部分内容转载自: http://jingyan.baidu.com/article/0aa22375bbffbe88cc0d6419.html http://www.aichengxu.com/view/35086 解决方法: 1. 进入Ubuntu启动菜单时按e 键进入启动项编辑模式: 2. 找到代码【ro rootflagsync】,将其…

android binder机制之——(创建binder服务)
Binder机制编程前面的几篇文章具体介绍了android中binder机制的方方面面,相信你对binder机制已经有了较深刻的理解。俗话说得好“学以致用”,以下我们就通过在android系统中创建一个我们自己的binder服务,来加深对binder机制的理解。…

通过NSProxy来解决NSTimer使用不当造成内存泄漏的问题
NSTimer的一般使用: 1 interface ViewController : UIViewController2 property (nonatomic, strong) NSTimer *timer;3 end4 5 implementation ViewController6 - (void)viewDidLoad {7 [super viewDidLoad];8 [self startTimer];9 } 10 11 - (void)startTimer { 12 …

Blender 2.9中的真实感三维产品全流程制作学习教程
MP4 |视频:h264,1280720 |音频:AAC,44.1 KHz,2 Ch 语言:英语中英文字幕(根据原英文字幕机译更准确) |时长:41节课(6h 23m) |大小:5.83 GB 含课程文件 使用blender 2.9建模、纹理、光照和渲染真实的吉他 …

SpringBoot中的SFL4J日志
SpringBoot:底层是Spring框架,Spring框架默认使用的是JCL日志的抽象层 SpringBoot选用SLF4J和logback 如何系统地在系统中使用SLF4J 在开发的使用,日志记录方法的调用,不应该来直接调用日志的实现类,而是调用日志抽象…

web开发性能优化---用户体验篇
怎样从技术角度怎样增强用户体验。都是非常多平台都在做的事情,依据个人实际经验碰到几种体验做下总结。1、降低页面刷新白屏适当使用ajax技术。改善刷新白屏现象。2、信息提醒,邮件、站内信、短信在购物流程、售后流程适当添加信息温馨提醒环节…

linux命令2--cd和pwd
2019独角兽企业重金招聘Python工程师标准>>> cd是linux中最为常见的一个命令,其作用就是切换到某一个路径下 例子1 到自己的用户目录下 cd ~ 也可以直接cd 例子2 返回进入当前目录之前的目录 cd - 例子3 把上一个命令作为cd的参数命令 cd !$ 参考文档&am…

COALESCE语句解救sql的sum问题
mysqlmybatis有一个sql语句是统计用的 <select id"getNum" resultType"map"> 结果是一个map, select语句的结果是一些sum select sum(t.anum),sum(t.bnum)from tableSum twhere t.id #{id} 调试发现,数据库明明记录已经落入&…

在UE5创造一个多山的松树森林场景学习教程
UE5游戏场景设计制作视频教程 大小解压后:4.37G 1920X1080 mp4 语言:英语中英字幕(机译)时长:5小时 20分 课程获取:在UE5创造一个多山的松树森林场景学习教程