Spring
一、概述
Spring功能非常丰富,核心的两大功能是:IOC、DI、AOP。
IOC:控制反转,指把创建对象的过程交给Spring
DI:依赖注入,指把对象间的依赖关系自动维护
AOP:面向切面编程,它是补充了OOP(面向对象)的不足
二、IOC(控制反转)
是指把创建对象管理对象的过程交给了Spring框架
1、IOC的XML实现方式
创建Maven的Module
导入jar包(被Spring Boot整合了)
创建IOCDemo类
public class IOCDemo {
public void ioc() {
System.out.println("我是Spring IOC的XML实现方式");
}
}
创建applicationContext.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"
xmlns:context="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">
<!--配置Bean的信息-->
<!--
id:作为这个bean的唯一标识,我们会通过这个获取,可以自行取名
class:类的全路径,找到需要的类
这个配置文件配置后,就会直接 new
IOC -> {"IOCDemo",new IOCDemo()},Map的{K,V}形式
底层反射
-->
<bean id="ioc" class="com.sgz.iocz.IOCDemo">
</bean>
</beans>
创建测试类
public class TestIOCAndDI {
@Test
public void test() {
// 1、读取配置文件
ClassPathXmlApplicationContext spring
= new ClassPathXmlApplicationContext("applicationContext.xml");
// 2、直接getBean,会得到new对象的地址值
// Object ioc = spring.getBean("ioc"); // 这里的 ioc 是 xml配置文件里的 id
// 因为ioc()方法在 IOCDemo,所有需要转换类型,并不在Object类中
IOCDemo ioc = (IOCDemo) spring.getBean("ioc");
// 3、调用该类的方法
ioc.ioc();
}
}
2、IOC的注解实现方式
创建IOCDemo02 类
/*
三种注解可以完成IOC: @Component、@Controller、@Service
Spring 框架提供的用来完成IOC,设置这些注解后,会被扫描到
以 Map -> {K,V}形式,ioc -> {"iOCDemo02",new IOCDemo02()}
*/
@Component("my") // 自定义bean的名字(对象名),我们就使用这名字就行了,不需要再使用默认的名字
// @Component
// @Controller
// @Service
public class IOCDemo02 {
public void ioc() {
System.out.println("我是Spring IOC的注解实现方式");
}
}
修改applicationContext.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"
xmlns:context="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">
<!--IOC包扫描-->
<!--
配置包扫描
它会帮我们new对象,IOCDemo02 iOCDemo02 = new IOCDemo02();
会自动生成默认名,一般都是首字母小写(有时候不会),注意看控制台打印提示对象名,也可以通过注解自定义对象名
base-package:指定一个包的路径,它只会扫描类中带有 @Component、@Controller、@Service 三者之一注解的
包可以 com.sgz.io 扫描该包下加了注解的类
com.sgz 扫描该包下所有包的类
com 扫描该包下所有包的类
-->
<context:component-scan base-package="com.sgz.iocz">
</context:component-scan>
</beans>
测试
public class TestIOCAndDI {
@Test
public void test() {
// 1、读取配置文件
ClassPathXmlApplicationContext spring
= new ClassPathXmlApplicationContext("applicationContext.xml");
// 2、直接getBean,会得到new对象的地址值
// IOCDemo02 iOCDemo02 = (IOCDemo02) spring.getBean("IOCDemo02");
IOCDemo02 iOCDemo02 = (IOCDemo02) spring.getBean("my"); //使用自定义bean名(对象名)
// 3、调用该类的方法
iOCDemo02.ioc();
}
}
三、DI(依赖注入)
1、概述
是指对象间的依赖关系,绑定两个类之间的关系,可以由框架来完成。
2、使用传统方式实现DI
创建Boss类
public class Boss {
String name = "我是老板";
@Override
public String toString() {
return "Boss{" +
"name='" + name + '\'' +
'}';
}
}
创建Staff类
public class Staff {
String name = "我是员工";
// 1、绑定两个类间的关系,在一个类中定义另外一个类的变量
private Boss boss;
// 2、get / set 方法
public Boss getBoss() {
return boss;
}
public void setBoss(Boss boss) {
this.boss = boss;
}
// toString用来测试显示数据
@Override
public String toString() {
return "Staff{" +
"name='" + name + '\'' +
", boss=" + boss +
'}';
}
}
配置包扫描
<?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/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">
<!--包扫描-->
<!--
配置包扫描
它会帮我们new对象,IOCDemo02 IOCDemo02 = new IOCDemo02(); Demo demo = new Demo();
会自动生成默认名,一般都是首字母小写(有时候不会),注意看控制台打印提示对象名,也可以通过注解自定义对象名
base-package:指定一个包的路径,它只会扫描类中带有 @Component、@Controller、@Service 三者之一注解的
包可以 com.sgz.io 扫描该包下加了注解的类
com.sgz 扫描该包下所有包的类
com 扫描该包下所有包的类
-->
<context:component-scan base-package="com.sgz.diz">
</context:component-scan>
</beans>
测试
public class TestIOCAndDI {
@Test
public void test() {
// 1、读取配置文件
ClassPathXmlApplicationContext spring
= new ClassPathXmlApplicationContext("applicationContext.xml");
// 2、实现传统DI
// Spring的DI传统实现(get,set)
Boss boss = new Boss();
System.out.println(boss); // Boss{name='我是老板'}
Staff staff = new Staff(); // Staff{name='我是员工', boss=null}
System.out.println(staff);
// DI:把两个对象间的关系依赖注入,实现DI
staff.setBoss(boss);
System.out.println(staff); // Staff{name='我是员工', boss=Boss{name='我是老板'}}
}
}
3、使用Spring注解实现DI
使用前必须加上@Component
注解简介
@Autowired:Spring中DI注解
创建Teacher类
@Component
public class Teacher {
String name = "我是老师";
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
'}';
}
}
创建Student类
@Component
public class Student {
String name = "我是学生";
/*
自动装配,该注解可以实现DI,不需要 get / set
使用DI前,必须有IOC,才可以DI,Component -> Autowired
*/
@Autowired
Teacher teacher;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", teacher=" + teacher +
'}';
}
}
创建配置文件,包扫描
<?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/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">
<!--包扫描-->
<!--
配置包扫描
它会帮我们new对象,IOCDemo02 IOCDemo02 = new IOCDemo02(); Demo demo = new Demo();
会自动生成默认名,一般都是首字母小写(有时候不会),注意看控制台打印提示对象名,也可以通过注解自定义对象名
base-package:指定一个包的路径,它只会扫描类中带有 @Component、@Controller、@Service 三者之一注解的
包可以 com.sgz.io 扫描该包下加了注解的类
com.sgz 扫描该包下所有包的类
com 扫描该包下所有包的类
-->
<context:component-scan base-package="com.sgz.diz">
</context:component-scan>
</beans>
测试
public class TestIOCAndDI {
@Test
public void test() {
// 1、读取配置文件
ClassPathXmlApplicationContext spring
= new ClassPathXmlApplicationContext("applicationContext.xml");
// 2、Spring的DI注解实现
Student student = (Student) spring.getBean("student");
System.out.println(student); // Student{name='我是学生', teacher=Teacher{name='我是老师'}}
}
}
总结
bean名不能一样
四、Lombok
1、作用
简化了Model层的代码的编写。
以前pojo类/实体类,需要自己提供set、get、toString、equals、hashCode。
Lombok通过各种注解,简化了以上操作。
2、注解简介
- @Data:会自动生成set、get、toString、equals、hashCode
- @NoArgsConstructor:自动生成无参构造
- @AllArgsConstructor:自动生成全参构造
- @Accessors(chain = true):开启链式编程
3、使用步骤
3.1、在IDEA里安装插件(高版本IDEA已经自动安装好,直接使用即可)
3.2、修改pom.xml文件,添加Lombok的jar包依赖,dependencies 标签内配置
<!--支持lombok-->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
</dependencies>
3.3、修改pojo包中的Shopping类
修改前
public class Shopping {
private Integer id;
private String name;
private Double price;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return "Shopping{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
'}';
}
}
修改后
@Data // 自动生成 get set toString equals hashCode
@NoArgsConstructor // 自动生成无参构造
@AllArgsConstructor // 自动生成有参构造
@Accessors(chain = true) // 开启链式编程
public class Shopping {
private Integer id;
private String name;
private Double price;
}
3.4、创建TestLombok测试类
修改前
public class TestLombok {
@Test
public void test(){
Shopping shopping = new Shopping();
shopping.setId(1);
shopping.setName("辣条");
shopping.setPrice(2.5);
System.out.println(shopping.getId());
System.out.println(shopping.getName());
System.out.println(shopping.getPrice());
System.out.println(shopping);
}
}
修改后
public class TestLombok {
@Test
public void test02(){
Shopping shopping = new Shopping();
shopping.setId(2);
shopping.setName("可乐");
shopping.setPrice(3.5);
System.out.println(shopping.getId());
System.out.println(shopping.getName());
System.out.println(shopping.getPrice());
System.out.println(shopping);
Shopping shopping1 = new Shopping(3,"雪碧",3.5);
System.out.println(shopping1);
Shopping shopping2 = new Shopping();
// 使用 Lombok 的链式编程
shopping2.setId(4).setName("鸡爪子").setPrice(2.5);
System.out.println(shopping2);
}
}
五、Spring MVC 与 Spring两个框架整合
1、创建网页
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>SpringMVC和Spring框架整合</title>
</head>
<body>
<a href="http://localhost:8080/two/get">点击请求服务器的数据</a>
</body>
</html>
2、创建包
3、创建启动类RunApp
// 自动配置了包扫描:默认从启动类所在的包以及它的子包开始扫描
@SpringBootApplication
public class RunApp {
public static void main(String[] args) {
SpringApplication.run(RunApp.class);
}
}
4、创建pojo包的Book类
/**
* 作者:沈公子
* 日期:2022/7/22 - 14:25
* 需求:模型层(M)
*/
@Data // 自动生成 get set toString equals hashCode
@NoArgsConstructor // 自动生成无参构造
@AllArgsConstructor // 自动生成含参构造
@Accessors(chain = true) // 开启链式编程
public class Book {
private Integer id;
private String name;
private String type;
private Double price;
}
5、创建controller包的BookController类
/**
* 作者:沈公子
* 日期:2022/7/22 - 14:27
* 需求:控制层(C)
*/
@RestController
@RequestMapping("two")
public class BookController {
// 想用那个类的功能,就 DI 过来(get / set)
// 调用 service 层的代码 DI
@Autowired
private BookServiceImpl service;
// 也可以使用接口
@Autowired
private BookService service1;
@RequestMapping("get")
public Object start() {
// 找 service 要数据,返回结果给浏览器
return service.get();
}
}
6、创建service包的BookService接口
/**
* 作者:沈公子
* 日期:2022/7/22 - 14:29
* 需求:Service接口
*/
public interface BookService {
// 接口里的方法都是抽象方法,而且都是public的,特殊的可以定义 default 和 static
// 获取书包数据
Book get();
// 增删改需不要返回值
// void add(Book book);
}
7、创建service包的BookServiceImpl实现类
/**
* 作者:沈公子
* 日期:2022/7/22 - 14:30
* 需求:Service实现类
*/
// IOC,使用DI前,需要IOC
@Component
public class BookServiceImpl implements BookService {
@Override
public Book get() {
// 给浏览器准备数据
Book book = new Book();
// Lombok的链式编程
book.setId(1).setName("SMM开发基础").setType("IT类").setPrice(60.5);
return book;
}
}
8、测试
六、Spring AOP(面向切面编程)
1、概念
AOP是一个面向切面编程的思想,它补充了面向对象的不足。
实现的效果:对方法的增强,本质上就是在执行方法的前后添加功能。
经典的使用场景:统计性能分析、权限管理、事务管理、日志、缓存…
切面:本质上就是一个类
通知:本质上就是一个方法,分成五类
具体五种为:
1. 前置通知before,方法执行前要执行的功能
2. 后置通知after,方法执行后要执行的功能
3. 环绕通知around,方法执行前后都要的执行的功能
4. 返回后通知argerReturning
5. 异常通知afterThrowing
切点:指定哪些类的哪些方法要用通知的功能。
2、AOP注解
- @Aspect:表示是一个切面类
- @Before:表示是一个前置通知
- @After:表示是一个后置通知
- @Around:表示是一个环绕通知
- @PointCut:表示切点
3、使用过程
3.1、导入jar包,pom.xml
<!--AOP依赖包-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.7.0</version>
</dependency>
</dependencies>
3.2、代码
// IOC才能调用里面的方法
@Service
// 标记着这是一个 AOP 的类:切面
@Aspect
public class AOPAspect {
// 1、切点(指定具体要用通知的类或者方法)
// 切点表达式:*是通配符,..表示0~n个
// 方法返回值 包路径 子包 类名 方法名 参数列表
@Pointcut("execution( * com.sgz.service..*.*(..))")
public void point() {
}
// 2、通知(是一个方法自定义功能)
@Around("point()") // 是一个环绕通知
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
long time = System.currentTimeMillis(); // 计时开始
// 去执行你的业务方法
Object o = joinPoint.proceed();
// long end = System.currentTimeMillis();
time = System.currentTimeMillis() - time; // 计时结束
// 获取类名和方法名
String methodname= joinPoint.getTarget().getClass().getName()+"."+joinPoint.getSignature().getName();
// end - start
System.out.println(methodname+"方法执行时间是:" + time);
return o;
}
}