简介
为什么要学习框架
框架相当于从小作坊到工厂的升级, 小作坊什么都要自己做, 工厂是组件式装配, 特点是高效.就好比开个餐厅,自己弄的话很麻烦, 需要考虑很多, 框架是加盟, 全部都由别人弄好, 自己经营
框架更加易用,简单且高效
优点
无需配置Tomcat, 点击运行即可运行项目. 因为SpringBoot内置了Web容器, 可以直接运行
快速添加外部jar包
快速发布项目, 使用java -jar xxx
即可发布
对象自动装配
Servlet和Spring对比
Servlet: 创建项目-补充目录-引入依赖-写代码-配置Tomcat-运行测试
Spring: 创建项目-写代码-运行测试
Servlet用context path
来区分业务, Spring用端口号
来区分
对于新增一个需求, Servlet新增一个类, Spring是新增一个方法. 更改请求类型, Servlet要把doGet改成doPost, 而Spring什么都不用做
Spring是个包含众多工具的IoC容器
容器
容器一般是指装东西的物体. 比如水杯装水,学校装老师学生, Tomcat装Web服务.而Spring就是存放对象的容器
IoC(Inversion of Control)
IoC是指控制反转, 是说控制权的反转.
例如class A里面实例化了一个MessageDao的对象, 那么这个对象的生命周期由对象A来管理. 而现在用Spring来管理对象的生命周期
传统思想开发&IoC
要制造一个车, 需要依赖车架,车架依赖底盘,底盘依赖轮胎.如果在构造方法里实例化依赖的对象, 如果发生了一点变化, 代码改动非常大, 因为互相嵌套. 用IoC则不会互相嵌套太多,只需要加属性和构造方法即可,不用担心嵌套.
IoC的优势就是程序解耦
DI:依赖注入
所谓依赖注⼊,就是由 IoC 容器在运⾏期间,动态地将某种依赖关系注⼊到对象之中。所以,依赖注⼊(DI)和控制反转(IoC)是从不同的⻆度的描述的同⼀件事情,就是指通过引⼊ IoC 容 器,利⽤依赖关系注⼊的⽅式,实现对象之间的解耦. IoC是一种思想, DI是实现
Spring的创建
过程
①创建一个空的maven项目
②引入Spring依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
③添加一个启动类
存对象
在resources
文件夹下创建一个.xml
文件, 名字无所谓,可以起spring-config.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">
</beans>
要存对象的话, 在里面写上如下内容,下面是创建两个对象`user1`和`user2`,类是`example.User`. 类要加上路径,方便区分
<?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="user1" class="example1.User"></bean>
<bean id="user2" class="example1.User"></bean>
</beans>
获取Spring上下文对象
①得到Spring上下文对象,因为对象都交给 Spring 管理了,所以获取对象要从 Spring 中获取,那么就得先得到 Spring 的上下⽂
②通过 Spring 上下⽂,获取某⼀个指定的 Bean 对象
③使⽤ Bean 对象
使用ApplicationContext获取对象
ApplicationContext context = new
ClassPathXmlApplicationContext("spring-config.xml");
使用BeanFactory获取对象
BeanFactory factory = new
XmlBeanFactory(new ClassPathResource("spring-config.xml"));
获取Bean对象
.getBean(id,class)
①根据xml里面对象的id来获取对象: 每个对象的id是唯一的User user1 = (User) context.getBean("user1");
②根据类来获取: 前提是xml里那个类只有一个对象, 好处是不需要类型转换User user2 = context.getBean(User.class);
③使用id和class一起来获取: 不用类型转换User user3 = context.getBean("user1",User.class);
注意点:
不论我们拿了多少次, 或者使用哪和方式取对象, 获取的都是同一个对象
BeanFactory&Applicationcontext区别
共同点:
都是获取spring bean的
不同点:
①Applicationcontext是BeanFactory的子类
父类的功能子类都有(国际化,环境,资源文件管理等…)
②性能
Applicationcontext提前把bean全部加载完,使用时候直接取出来(空间换时间)
BeanFactory是懒加载的模式,使用的时候采取创建(时间换空间)
更简单的存对象
过程
①配置扫描路径:首先在xml文件里加上:<content:component-scanbase-package="com.bite"></content:component-scan>
引号里写的是需要扫描的路径
②加上注解, 还可以自定义名称
③使用对象
五大类注解
一般情况是新建一个包专门用来被扫描, 包的子目录有5个,分别是五大注解的名字:Controller(控制器存储)
,Service(服务存储)
,Repository(仓库存储)
,Component(组件存储)
,Configuration(配置存储)
@Controller:表示的是业务逻辑层. 控制器,通常是指程序的入口,比如参数校验,参数类型转换...前置处理工作
@Servie:服务层.一般写业务代码,服务编排
@Repository:持久层.通常是指DB操作相关的代码
@Configuration:配置层
使用类对象的时候:如果没有重命名, 使用类名的首字母小写即可选中使用哪个类.当类名前两个字母都是大写的时候,首字母小写就不行了,要用原名
使用方法(都一样)
注解存储对象:
@Controller // 将对象存储到 Spring 中
public class UserController {
public void sayHi(String name) {
System.out.println("Hi," + name);
}
}
使用对象:
public class Application {
public static void main(String[] args) {
// 1.得到 spring 上下⽂
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
// 2.得到 bean
UserController userController =
(UserController) context.getBean("userController");
// 3.调⽤ bean ⽅法
userController.sayHi("Bit");
}
}
重命名
注解后面加上名字即可, 例如:@Controller("usercontroller")
方法注解@Bean
使用
@Bean需要搭配五大注解使用
@Component
public class Users {
@Bean
public User user1() {
User user = new User();
user.setId(1);
user.setName("Java");
return user;
}
}
@Bean对应生产的bean名称是方法名
public class Application {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
User user = (User) context.getBean("user1");
System.out.println(user.toString());
}
}
重命名
①重命名的name是一个数组,一个bean可以有多个名字, 例如:@Bean(name={"u1","u2"})
②name={}可以省略, 例如:@Bean({"u1","u2"})
为对象设定属性值
**设定属性的时候必须要保证有对应的构造函数,不然会报错**
方法注解传参
如果传的参数类型只有一个对象,那么就自动用那个对象,尽管名字不匹配
如果传的参数类型有多个对象,那么按照名字匹配,名字配不上就报错
xml文件传参
用xml不加注解(虽然加了也不会报错. 注解和xml的id重复没事,但id和id之间绝对不能重复).
<bean id="userController" class="com.controller.UserController">
<constructor-arg name="name" value="zhangsan"></constructor-arg>
</bean>
注意事项
如果传参的时候,传入的参数类型是引用数据类型, 那么xml的value="xxx"
要改成ref="xxx"
<bean id="userController" class="com.controller.UserController">
<constructor-arg name="name" value="zhangsan"></constructor-arg>
</bean>
对象装配(属性注入/依赖注入)
上面的方法太麻烦
属性注入@Autowired
通过加@Autowired
注解注入: 不用写xml,不用写构造函数
UserController依赖UserService, 给UserService加注解. 虽然官方不推荐使用, 但是实际开发中使用最多
这里的注入也是按照下面的方式匹配
特点:
Setter方法注入
用Setter方法给us设置属性值, 然后给Setter方法加上注解@Autowired
特点:
构造函数注入
一个类默认有一个无参的构造函数. 当我们写了有参的构造函数, 就没有这个默认的无参构造函数了
创建对象需要调用构造函数
当前存在多个构造函数, spring就不知道用哪个构造函数, 所以会报错, 我们需要告诉Spring,使用哪个构造函数. 给要用的构造函数加注解既可以告诉spring
特点:
@Resource注入(JDK提供)
@Resource
可以改名字:@Resource(name="user")
@Autowired
不能这么改,改的话要再加一个@Qualifier(value="user")
来重命名
Bean作用域
singleton 单例作用域
无状态是指对象的状态不需要更新, 属性值都不会变化
ScopeController将user名字改成"张三获取的User", 之后scopeController2调用sayHi方法,结果也是"张三获取的User". 因为是单例模式, 对象都是同一个, 名字被改了其他调用者也用的是被改的名字
可以在@Bean注解前加一个@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
可以简写成@Scope("prototype")
让他变成多例模式.
prototype 原型作用域(多例作用域)
request 请求作用域
session 会话作用域
application 全局作用域
websocket HTTPWebSocket作用域
Bean的生命周期
实例化Bean
为Bean分配内存空间(不等于初始化).
设置属性
Bean的注入和装配