目录
2.框架优点展示(SpringBoot VS Servlet)
IOC容器 vs 传统开发 => 其实就是理解IoC的概念及作用
1.为什么要学框架?
随着技术发展,第三方框架使用的越来越多,几乎所有的java项目都会使用的基础框架,叫做javaee框架;我们学习的基础框架SSM => 几大框架的简称:
Spring Framework+SpringMVC+MyBates
Spring Framework:基础框架,包含很多组件
SpringMVC:web开发
MyBates:操作数据库的框架
基于这些框架,对比之前的servlet、jdbc,灵活性,易用性,扩展性有很大提升。
2.框架优点展示(SpringBoot VS Servlet)
使用 Spring Boot 项目演示框架相比于 Servlet 所具备的以下优点:
- 无需配置 Tomcat,点击“运行”按钮就可以运行项目,Spring Boot 内置了 Web 容器(可直接运行)。
- 快速添加外部 jar 包。
- 快速发布项目(使用 java -jar 方式就可以发布)。
- 对象自动装配。
Servlet 痛点分析
- 添加外部 jar 不方便,容易出错,比如添加了一个不匹配的外部 jar 版本;
- 运行和调试的时候需要配置 tomcat 不方便;
- 发布不方便,servlet 项目必须依靠外置的 tomcat(外置的 web 容器)运行。
- 路由配置不方便,一个访问地址对应一个 Servlet 类。
SpringBoot 相比于 Servlet 的优点总结:
- 添加外部 jar 更容易,不易出错(版本问题无需关注);
- 调试项目更加方便,无需配置 Tomcat;
- 发布项目更加方便,无需配置 Tomcat;
- 添加路由更加方便,无需每个访问地址都添加一个类。
3.Spring 框架:Spring Framework
Spring框架包含了很多组件:Spring容器/IoC 容器。SpringMVC,SpringAOP。
3.1 IoC容器/Spring容器
对于Spring IoC容器来说,是管理Bean对象的容器。
Bean对象:普通的Java实例对象,单纯从存放数据(对象)这个角度角度,和集合框架一模一样
但是其次还是有区别的;
- 使用集合存放队象:程序自己new,存储数据,调用队象的方法;
- 使用Spring容器存放队象:程序不需要自己去new,某些符合框架约定的方法是框架自动调用;(需要框架管理,才放进去(不用程序员自己new);不需要框架管理的,当然还是要自己去new。)
IOC容器 vs 传统开发 => 其实就是理解IoC的概念及作用
传统开发:自己创建对象及组织对象之间的依赖关系(对象属性,依赖(引用)另一个对象)
loC:控制反转
实例化对象,及组织对象间的依赖关系,都转交给loC容器来进行管理
控制权由程序自己控制,转变为loC容器控制,控制权发生反转,所以称为loC容器;因为是Spring框架中使用,所以也叫Spring容器
使用IoC容器:按照框架约定的写法,就可以实现,框架统一管理Bean对象的生命周期(new,某些生命周期方法),Bean队象之间的依赖关系。
3.2 DI:依赖注入
是从不同角度描述的同一个事情
由IoC容器,运行时,组织对象之间的依赖关系(对象中的依赖(引用),框架给我们注入)
IoC 和 DI 的关系
IoC是一种设计思想,他的实现方式包括IoC容器,而IoC容器的实现方式包括DI。
作用
解耦:自己写的代码来创建的队象及组织依赖关系,是强耦合的(一个对象需要修改代码,其他依赖这个对象的地方,也得改)。使用框架后,框架会给我们自动组织依赖关系,解耦。
4.开发方式
4.1 搭建环境
建议:使用一个SpringBoot项目基础模板(pom.xml)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 默认使用的Spring Framework版本为5.2.10.RELEASE -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.example</groupId>
<artifactId>ee-first</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- spring-boot-starter-web: 基于SpringBoot开发的依赖包,
会再次依赖spring-framework中基本依赖包,aop相关依赖包,web相关依赖包,
还会引入其他如json,tomcat,validation等依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- 排除tomcat依赖 -->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 添加 Undertow 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<!--引入AOP依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- spring-boot-devtools: SpringBoot的热部署依赖包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<!-- 不能被其它模块继承,如果多个子模块可以去掉 -->
<optional>true</optional>
</dependency>
<!-- lombok: 简化bean代码的框架 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- spring-boot-starter-test: SpringBoot测试框架 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<!-- SpringBoot的maven打包插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
4.2 开发步骤
package org.example.model;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
//以下四个注解,都是类注解,用于注册Bean对象
//注册的方式,默认的Bean ID(名称),是类名首字母小写
@Controller
//@Service
//@Repository
//@Component
public class Bean对象1 {
public void sayHello(){
System.out.println("Hello");
}
}
package org.example;
import org.example.config.AppConfig;
import org.example.model.Bean对象1;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Spring容器启动类 {
public static void main(String[] args) {
//ApplicationContext就是Spring容器的顶级接口
//AnnotationConfigApplicationContext是其中的一个实现类,它的作用是:
//(1)扫描指定的包路径下,使用Spring框架注解的类
//(2)注册这些类到容器中=>框架帮我们new对象,及注入对象的依赖关系(属性赋值)
ApplicationContext context = new AnnotationConfigApplicationContext("org.example");
//获取Bean对象有两种方式:
//(1)通过bean的类型
Bean对象1 b1_1 = context.getBean(Bean对象1.class);
System.out.println(b1_1);
//(2)通过bean的id(也叫bean的名称,首字母小写)
Bean对象1 b1_2 = (Bean对象1) context.getBean("bean对象1");//这个方法要强制转换一下
System.out.println(b1_2);
}
}
4.3 注意事项
1.一定要被扫描到;
2.默认注册到容器中的bean id(名称),是类名的小写字母
3.默认类注解(默认都是单例的方式注册):
- @Controller
- @Service
- @Repository
- @Component
- @Configuration
1~4是注册为普通的java bean对象;5是注册为配置类对象(项目启动时,需要准备一些配置信息或资源,一般通过配置来初始化)。
5.程序的工程分层(不同的类注解,是用于不同的软件分层中)
@Configuration:容器启动,就初始化配置(自己设置初始化的时机)
@Controller:接受HTTP请求并返回相应
@Service:处理业务逻辑的分层
@Repository:数据访问分层:一般是数据库的操作
@Component:一般组件使用,除了以上明确含义的类注解作用,之前的作用就可以使用@Component注解
//@Controller、@Service、@Repository这三者之间,是有一定的依赖(引用)关系
@Controller
public class XXXController{
//这里会添加其他一些注解,表示注入bean对象
private XXXService xxxService;
}
@Service
public class XXXService{
//注入bean对象的注解
private XXXRepository xxxRepository;
}
@Repository
public class XXXRepository {
}
要明确理解:
- 注册bean对象:按框架约定写法(目前是几个类注解),框架给我们new对象
- 注入依赖关系:按框架约定写法(属性注解),框架给我们组织依赖关系(把容器中的对象赋值给属性)
6.注册bean对象
(1)类注解:5种
- @Controller
- @Service
- @Repository
- @Component
- @Configuration
(2)方法注解
@Bean => 只有类被扫描到,且注册到容器中,方法上的@Bean注解才生效
=> @Bean注解的方法,所在的类,需要以上5种类注解之一
=> 一般,是在@Configuration配置类中,使用,比较规范
package org.example.config;
import org.example.model.Bean对象2;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
//方法上,使用@Bean表示注册一个Bean对象到容器中
//方法的名称,就是bean ID/名称
//方法的返回值,就是注册的实例对象
//一般是public修饰的实例方法
@Bean
public Bean对象2 testBean2_1(){
// return new Bean对象2();
Bean对象2 bean = new Bean对象2();
bean.setName("bean2_1");
return bean;
}
@Bean
public Bean对象2 testBean2_2(){
// return new Bean对象2();
Bean对象2 bean = new Bean对象2();
bean.setName("bean2_2");
return bean;
}
}
package org.example;
import org.example.config.AppConfig;
import org.example.model.Bean对象2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Spring容器启动类 {
public static void main(String[] args) {
//ApplicationContext就是Spring容器的顶级接口
//AnnotationConfigApplicationContext是其中的一个实现类,它的作用是:
//(1)扫描指定的包路径下,使用Spring框架注解的类
//(2)注册这些类到容器中=>框架帮我们new对象,及注入对象的依赖关系(属性赋值)
ApplicationContext context = new AnnotationConfigApplicationContext("org.example");
//获取注册到容器中的配置类对象
AppConfig config = context.getBean(AppConfig.class);
System.out.println(config);
//@Bean方法注册到容器的对象
Bean对象2 b2_1 = (Bean对象2) context.getBean("testBean2_1");
System.out.println(b2_1);
b2_1.setName("修改后2-1");
Bean对象2 b2_2 = (Bean对象2) context.getBean("testBean2_2");
System.out.println(b2_2);
//@Bean方法注解,注册到容器中,可以是同一个类型的不同实例对象
//此时,如果通过类型,获取bean对象,就会报错:
//容器中,一个类型,有多个实例对象,通过类型就不知道获取哪个了
// Bean对象2 b2_1_byType = context.getBean(Bean对象2.class);
// System.out.println(b2_1_byType);
}
}
一个类型,可以注册多个实例对象
但这样获取bean对象,就只能使用bean id/名称来获取
使用类型获取,就会报错