Sping
系统:Windows
编译器:IDEA2021
创建JAVAEE(Spring)项目
诺是没有发现自己有Spring installer 这个是要安装插件的。
搜索就好。安装第一个
注意:此时网络一定要好,不然下载依赖会出现问题。在下载之前我们需要先检查是否是国内源,需要勾选一些选项。
通过下面的地址我们去看看seting中是否存在国内源。
刷新一下(重新加载):
诺是出现下载失败的问题很正常。我这里用一个我所处理的方式。删除maven中的plugins中的文件,重新在网络好的地方下载。
等待就好了。但是如果阿里源出现的问题,就需要去之前seting位置里将阿里源换了就好。这里的源最好自己去找新的。不然小心出问题。
到这里我们的Spring项目就创建好了
Spring框架
SpringBoot VS Servlet
使⽤ Spring Boot 项⽬演示框架相⽐于 Servlet 所具备的以下优点:
- ⽆需配置 Tomcat,点击“运⾏”按钮就可以运⾏项⽬,Spring Boot 内置了 Web 容器(可直接运⾏)。
- 快速添加外部 jar 包。
- 快速发布项⽬(使⽤ java -jar ⽅式就可以发布)。
- 对象⾃动装配。
Spring 核心(Spring Framework(开源框架))
Spring是包含了众多⼯具⽅法的 IoC 容器。什么是容器:就是盛放某种物品的装置。
IoC容器(Spring)
IoC=inversion of Control 翻译成中文是“控制反转”的意思,(控制(权)翻转)
控制什么?对象的生命周期,对象不由人或者当前代码来控制,而是交给Spring来控制—》及控制权反转。当需要new对象时,从容器中取得。
Ioc优点:
可以实现解耦合(松耦合)
(什么是耦合,代码耦合:比如一辆车,一个车是由车身构成,车身有车底,而车底是有轮子的。)
如果我们对这个一个车进行构造,我们要怎么做。
车—>车身—>车身—>轮胎
车依赖于车身,车身依赖于车底,车底依赖于轮胎。一辆现实中的车,尺寸大小是一定的。但是车子种类很多。现在有一个人对车的轮胎有要求,那么工厂对应相应的轮胎需要去定制相应的底盘,而定制的底盘又有相应的车身与之对应,相应的车身就构成了不同型号的车子。简单而言就是牵一发而动全身。(非常的不方便,修改成本太高了)这种情况就称之为耦合。此时耦合度很高。
我们实现代码需要高内聚低耦合。
为了解决在这个问题,IoC机制应运而生。(依赖注入)
SpringIoC
既然Spring是一个IoC(控制反转)容器,重点还在“”容器“意味着他有两个重要的功能;
- 对象存入到容器中
- 从容器中取出对象。
Spring 是⼀个 IoC 容器,说的是对象的创建和销毁的权利都交给 Spring 来管理了,它本身⼜具备了存储对象和获取对象的能⼒。
Spring(Ioc)容器管理的资源->对象->bean
DI(依赖注入):
DI:Dependency Injection 的缩写,翻译成中⽂是“依赖注⼊”的意思。
依赖注入:就是由 IoC 容器在运⾏期间,动态地将某种依赖关系注⼊到对象之中。
依赖注⼊(DI)和控制反转(IoC)是从不同的⻆度的描述的同⼀件事情,就是指通过引⼊ IoC 容器,利⽤依赖关系注⼊的⽅式,实现对象之间的解耦。
二者之间的区别:
DI(依赖查找)是一种实现方式IoC:
(DF(依赖查找)也能实现IoC)
IoC是一种思想原则:
创建使用Spring
-
创建一个普通的mave项目
-
添加Spring框架(Spring-context,Spring-beans)
导入依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
</dependencies>
- 添加启动类
存储Bean对象到Spring中
- 将对象存储到容器中
创建一个Bean对象:就是一个普通的对象
将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:content="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">
</beans>
这样就将这个类放进了Spring中。
获取并使用Bean对象
获取并使⽤ Bean 对象,分为以下 3 步:
-
得到 Spring 上下⽂对象,因为对象都交给 Spring 管理了,所以获取对象要从 Spring 中获取,那么就得先得到 Spring 的上下⽂。
-
通过 Spring 上下⽂,获取某⼀个指定的 Bean 对象。
-
使⽤ Bean 对象。
context.getBean(),获取对象是object,所以需要向下转型(强转)
运行后我便得到了结果。
ApplicationContext vs BeanFactory
相同点:
都是容器对象,都可以获取Bean对象
不同点:
ApplicationContext 是BeanFactory的子类,所以前者拥有更多的功能(国际化支持,资源访问支持,以及时间传播等方面的支持)
加载Bean机制不同:BeanFactory按需加载(懒加载),使用一个bean加载一个bean。ApplicationContext 一次性加载所有bean对象。BeanFactory加载快但是,搜索相应的bean速度比较慢,ApplicationContext 加载慢,但是搜索快。
getBean的用法
用法1. 更据名称获取Bean对象
Megger megger =(Megger)context.getBean(“user”);
用法2:根据类型获取对象。
Megger megger1=(Megger)context.getBean(Megger.class);
但是这种可能会出问题,同一个类型注入到Spring多个情况下,那么使用类型获取就会报错。
用法3.根据类型+根据名称
Megger megger=context.getBean(“user”,Megger.class);
优雅和稳妥。
注解
前置工作(不配置注解用不了):
在 spring-config.xml 添加配置:
<content:component-scan base-package=“com.xie.demo”></content:compon
ent-scan>
package后面的目录一定要适量,不然范围小了,没用,大了扫描太慢了。
添加注解存储 Bean 对象
想要将对象存储在 Spring 中,有两种注解类型可以实现:
类注解:
-
@Controller(控制器)验证参数的合法性(接收前端请求)
-
@Service(服务)业务组装(客服中心)
-
@Repository(数据层)实际业务处理,(数据存储)
-
@Component(组件)工具类(基础工具)(公共)
-
@Configuration(配置层)配置(系统)
⽅法注解:
- @Bean
更加简单的对bean存储
- 通过类注解实现Bean对象的存储
注解在不设置命名的时候,注解默认类名的首字母小写 做命名。
注解和xml是可以混用。
当类的首字母和第二个字母都大写时,注解不设置命名,引用时使用原类名就行。否则会报错 原因使Spring调用了java基本库里的命名方式。
基本业务逻辑:
- 通过方法注解实现Bean对象的存储
将当前方法返回的对象存储到IoC容器
使用Bean的注意事项:
@Bean注解必须要配合类注解使用。
这种情况下呢,这个类加入了类注解,也会存到Spring容器中。并且这个类下的所有方法都会注入Spring容器。
注意:@Bean没有起名字:默认命名=方法名
框架里面是很少出现重载的,使用框架不要使用重载。@Bean的方法是无法传入参数的。
@Bean的重命名
- 方式1:@Bean({“XXX”})
- 方式2:@Bean(name={“XXX”})
- 方法3:@Bean(value={“XXX”,“XXX”})
可以设置多个名字,获取。
当@Bean重命名之后,那么默认命名方式就不能使用了。
重命名情况:
如果多个Bean使用相同的名称,那么程序执行不会报错,但是第一个Bean之后的对象不会被存放到容器中,也就是只有在第一次创建Bean的时候会将名称和Bean名称关联起来,后续再有相同名称的Bean存储时候,容器会自动忽略。
获取Bean对象
对象装配
1.属性注入(DI依赖注入)
@Autowired
@Repository
public class UserRepository {
public int add(){
System.out.println("Repository");
return 0;
}
}
@Service
public class UserService {
@Autowired//DI 依赖注入
private UserRepository userRepository;
public int add(){
System.out.println("Service");
return userRepository.add();
}
}
依赖注入问题:
同类型的Bean的存储到容器多个,获取时,会报错。
- 将Autowired注入的属性换成对应的方法的名。及属性的名字和Bean的名字对应上
(也就是改成user1或者user2)
- @Autowired配合@Qualifier一起使用
缺点是: - 无法注入final修饰的变量
1.将final修饰的变量需要直接赋值
2.在构造方法中进行赋值
- 通用型问题
1.只适用与IoC容器
- 设计原则问题
1.更容易违反单一设计原则。因为使用起来比较简单。
2.构造方法注入(官方推荐)
Spring(4.0以后)
@Service
public class UserService3 {
private UserRepository userRepository;
@Autowired
public UserService3(UserRepository userRepository){
this.userRepository=userRepository;
}
public void sayHi(){
System.out.println("service4");
userRepository.add();
}
}
单个构造方法:Autowired可以不加。
优点:
可以注入一个final修饰的变量。
- 注入的对象不会被修改,因为构造方法只会加载一次
- 构造方法注入可以保证注入对象完全初始化。
- 构造方法注入通用性更好
缺点:
- 写法比属性注入复杂
- 使用构造方法注入,无法解决循环依赖(三级缓存)的问题
3.Setter注入(重要)
@Service
public class UserServcie2 {
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
public void sayHi(){
System.out.println("service2");
userService.add();
}
}
优点:
更符合单一设计原则,Setter更符合单一设计原则。
缺点:
- 无法注入一个final修饰的变量 setter注入的对象可以被修改,
- setter本来就是一个方法,既然是一个方法就有可能被多次调用和修改。
DI依赖注入 VS DF依赖查找
- 依赖查找,依赖于Bean名称
- @Autowired依赖注入流程:先根据getType(从容器中)获取对象,如果只获取一个,那么直接将此对象注入到当前属性上;如果获取到多个对象,才会使用getName(根据名字)进行匹配。
通用性: 构造 > setter > 属性
补充:
@Resource:来自于java(也可以注入)
@Autowired vs @Ressource
1.出身不同:@Ressource来自于JDK;@Autowired 来自于Spring框架
在专业版,某些时候Autowired会报错(报错),但是项目是可以执行的。诺是Spring在代码执行之后再去执行,java是不知道这个属性是否注入的。
2.参数设置不同:@Ressource 支持很多参数,@Autowired支持一个参数设置
3.使用区别:@Resource不支持构造方法注入,@Autowired只支持构造方法注入。
4.idea兼容性支持不同,使用@Autowired在idea的专业版下可能会报错;@Resource不存在误报问题