Spring
1.1简介
- Spring:春天—->给软件行业带来了春天!
- 2002,首次推出了Spring框架的雄性:interface21框架!
- Spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日发布了1.0正式版
- Rod Johnson Spring Framework创始人,著名作者,很难想象Rod Johnson的学历,真的让好多人大吃一惊,他是悉尼大学的博士,然而他的专业不是计算机,而是音乐学
- Spring理念:使现有的技术更加容易使用,本事是一个大杂烩,整合了现有的技术框架
- SSH:Struct2 Spring Hibernate
- SSM:SpringMVC Spring Mybatis
代码语言:javascript复制官网:https://spring.io/ Spring Framework 5.3.12 API:https://docs.spring.io/spring-framework/docs/current/javadoc-api/ Version 5.3.12:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#spring-core 官方下载地址:https://repo.spring.io/ui/native/release/org/springframework/spring/
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.12</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbk</artifactId>
<version>5.3.12</version>
</dependency>
1.2、优点
- Spring是一个开源的免费的框架(容器)!
- Spring是一个轻量级的、非入侵式的框架!
- 控制反转(IOC),面向切面编程(AOP)
- 支持事务的处理,对框架的整合的支持
==总结:Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架!==
1.3、组成
1.4、拓展
在Spring的官网有这个介绍:现代化的Java开发!也就是基于Spring的开发
- Spring Boot
- 一个快速开发的脚手架
- 基于SpringBoot可以快速的开发单个微服务
- 约定大于配置
- Spring Cloud
- SpringCloud是基于SpringBoot实现的
因为现在大多数公司都在使用SpringBoot进行快速开发,学习SpringBoot的前提,需要完全掌握Spring及SpringMVC!承上启下的作用
弊端:发展了太久之后,违背了原来的理念,配置十分繁琐,人称:“配置地狱”
2.IOC理论推导
- UserDao接口
- UserDaoImpl实现类
- UserService业务接口
- UserService业务实现类
在我们之前的业务中,用户的需求可能会影响我们原来的代码,因为我们需要根据用户的需求修改源代码!如果程序代码量十分大,修改一次的成本代价十分昂贵!
我们使用一个Set接口实现,已经发生了革命性的变化
代码语言:javascript复制private UserDao userDao;
//利用set进行动态实现值的注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
- 之前,程序是主动创建对象!控制权在程序猿手上!
- 使用了Set注入后,程序不再具有主动性,而是变成了被动的接受对象!
这种思想,从本质上解决了问题,我们程序员不用在去管理对象的创建了。系统的耦合性大大降低!可以更加专注这种在业务实现上!这是IOC的原型
IOC本质
控制反转IOC(Inversion of Control),是一种设计思想,ID(依赖注入)是实现IOC的一种方法
控制反转是一种通过描述(XML或注解)并通过第三方去生产获取特定对象的方式,在Spring中实现控制反转的是IOC容器,其实方法是依赖注入
3.HelloSpring
控制:传统应用程序的对象是有程序本身控制创建的,使用Spring后,对象是由Spring来创建的
反转:程序本身不创建对象,而变成被动的接受对手
依赖注入:就是利Set方法来实现注入的
IOC是一中编程思想,由主动的编程变成被动的接受
4.IOC创建对象的方式
- 下标赋值
<!-- 有参构造 1.下标赋值-->
<bean id="user" class="com.hgm.pojo.User">
<constructor-arg index="0" value="黄帅哥"/>
</bean>
- 类型赋值
<!-- 有参构造 2.通过类型创建,不建议使用 -->
<bean id="user" class="com.hgm.pojo.User">
<constructor-arg type="java.lang.String"value="黄帅哥"/>
</bean>
- 参数名
<!-- 3.直接通过参数名来设置-->
<bean id="user" class="com.hgm.pojo.User">
<constructor-arg name="name" value="黄帅哥"/>
</bean>
总结:在配置文件加载的过程中,容器中管理的对象就已经初始化了
5.Spring依赖注入
5.1别名
代码语言:javascript复制<!-- 别名,如果添加了别名,可以通过别名调用-->
<alias name="userT" alias="abc"/>
5.2Bean配置
代码语言:javascript复制<!--
id:bean的唯一标识符,也就是对象名
class:bean对象所对应的全限定名:包名 类型
name:也是别名,而且name可以取多个别名
-->
<bean id="userT" class="com.hgm.pojo.UserT" name="u2,user2 u3">
<property name="name" value="黄帅逼"></property>
</bean>
5.3import
这个import,一般用于团队开发使用,他可以将多个配置文件,导入合并为一个
代码语言:javascript复制<import resource="beans.xml"/>
6.依赖注入
7.Bean的自动装配
7.1测试
7.2ByName自动装配
7.3ByType自动装配
代码语言:javascript复制<context:annotation-config/> <bean id="cat" class="com.hgm.pojo.Cat"/> <bean id="dog" class="com.hgm.pojo.Dog"/> <!-- Bean自动装配 byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean id, 需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致 byType:会自动在容器上下文中查找,和自己对象属性相同的bean, 需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型值一致 --> <bean id="people" class="com.hgm.pojo.People"> <property name="name" value="黄帅哥"/> </bean>
小结:
- byname的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致
- ByType的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型值一致
7.4 使用注解实现自动装配
jdk1.5支持的注解,Spring2.5就支持注解了!
要使用注解须知:
代码语言:javascript复制 1. 导入约束 context约束2. ==配置注解的支持 <context:annotation-config/>==
代码语言:javascript复制<?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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config/></beans>
@Auotwired
直接在属性上使用即可! 也可以在set方式上使用
使用Auotwired我们可以不用编写Set方法了,前提是你这个自动导入装配的属性在IOC (Spring) 容器中存在,且符合名字Byname
科普: @Nullable字段标记了这个注解,说明这个字段可以为null
代码语言:javascript复制public @interface Autowired { boolean required() default true;}
测试代码
代码语言:javascript复制public class People { // 如果显示定义了Auotwired的required属性为false,说明这个对象可以为null,否则不允许为空 @Autowired(required = false) private Cat cat; @Autowired private Dog dog; private String name;}
@Autowired和@Qualifier(value = “xx”)配合使用
如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解[@Autowired]完成的时候,我们可以使用@Qualifier(value = “xx”)去配置@Autowired的使用,指定一个唯一的bean对象注入!
代码语言:javascript复制public class People { @Autowired @Qualifier(value = "cat11") private Cat cat; @Autowired @Qualifier(value = "dog222") private Dog dog; private String name;}
@Resource注解
代码语言:javascript复制public class People { @Resource(name = "cat2") private Cat cat; @Resource private Dog dog; private String name;}
小结:
@Resource和@Auotwired的区别:
- 都是用来自动装配的,都可以放在属性字段上
- @Auotwired 是通过Byname的方式实现,而且必须要求这个对象存在[常用]
- @Resource 默认是通过byname的方式实现,如果找不到名字,则通过byType实现,如果两个都找不到的情况下就报错!
- 执行顺序不同:@Auotwired 通过byType的方式实现.@Resource 默认是通过byname的方式实现,
8.使用注解开发
在spring4之后,要使用注解开发,必须保证aop的包导入了
使用注解需要导入context约束,增加注解的支持
代码语言:javascript复制<?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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/></beans>
注册bean Component代替了
属性如何注入 @Value(“SerMs”)
代码语言:javascript复制//等价于 <bean id="user" class="com.hgm.pojo.User"/> Component:组件@Componentpublic class User { public String name; //相当于 <property name="name" value="SerMs"/> @Value("SerMs") public void setName(String name) { this.name = name; }}
衍生的注解(在类里面使用了注解就说明这个类被Spring托管了,也就是成为Spring的组件了)
- @Component有几个衍生注解,我们在web开发中,会按照MVC三层架构分层!
- dao层【@Repository】 (dao层我们都会用Repository来注解)
- service层【@Service】(service层我们都会用Serivce来注解)
- Controller层【@Controller】
这四个功能都是一样的,都是代表将某个类注册到Spring中,装配Bean
自动装配
- @Auotwierd:自动装配通过类型、名字
- 如果Auotwierd不能唯一自动装配上属性,则需要通过@Qualifier(value=”xxx”)
- @Nullable:字段标记了这个注解,说明这个字段可以为null
- @Resource:自动装配通过名字,类型
作用域
代码语言:javascript复制@Component //注入 bean@Scope("singleton") //singleton 单例模式,prototype原型模式 作用域public class User { public String name; //相当于 <property name="name" value="SerMs"/> @Value("SerMs") //注入值 Value public void setName(String name) { this.name = name; }}
小结
xml与注解:
- xml更加万能,使用宇任何场合,维护更加方便
- 注解 不是自己类使用不了,维护相对复杂!
xml与注解最佳实践:
xml用来管理bean
注解只负责属性的注入
我们在使用的过程中,只需要注意一个问题,必须让注解生效,就需要开启注解的支持
```xml
代码语言:javascript复制
----
#### 注解说明
- @Auotwierd:自动装配通过类型、名字
- 如果Auotwierd不能唯一自动装配上属性,则需要通过@Qualifier(value="xxx")
- @Nullable:字段标记了这个注解,说明这个字段可以为null
- @Resource:自动装配通过名字,类型
- @Component:组件,放在类上,说明这个类被Spring管理了,就是bean
---
### 9.使用Java的方式配置Spring
我们现在要完全不使用Spring的xml配置了,全权交给Java来做
JavaConfig是Spring的一个子项目,在Spring4之后他成为了一个核心功能
![image-20211028202432188](C:Users江小白AppDataRoamingTyporatypora-user-imagesimage-20211028202432188.png)
###### **实体类**
```java
//这里这个注解的意思,就是说明这个类被Spring接管了,注册到了容器中@Controllerpublic class User { @Value("SerMs") //属性注入值 private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" "name='" name ''' '}'; }}
配置文件
代码语言:javascript复制package com.hgm.pojo;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Import;/** * @author Ser_Ms * @version 1.0 * @Date 2021/10/28 20:20 */@Configuration //这个也会Spring容器托管,注册到容器中,因为他本来就是一个Component// @Configuration代表这是一个配置类,就和我们之前看的bean.xml一样的@ComponentScan("com.hgm.pojo")@Import(MyCofig2.class)public class MyConfig { //注册一个Bean,就相当于我们之前写的一个bean标签, //这个方法的名字就是相当于bean标签中的id属性, //这个方法的返回值,就相当于bean标签中的class属性, @Bean public User getUser(){ return new User(); //就是返回要注入到bean的对象 }}
测试类
代码语言:javascript复制public class MyTest07 { public static void main(String[] args) { //如果完全使用了配置类方式去做,我们就只能通过AnnotationConfig上下文来获取容器,通过配置类的class对象加载! ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class); User getUser = context.getBean("getUser",User.class); System.out.println(getUser.getName()); }}
这种纯Java的配置方式,在SpringBoot中随处可见
10.代理模式(AOP)
为什么要学习代理模式?因为这就是SpringAOP的底层!【SpringAOP和SpringMVC】
代理模式的分类:
- 静态代理
- 动态代理
10.1静态代理
角色分析:
- 抽象角色:一般会使用接口或者抽象类来解决
- 真实角色:被代理角色
- 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作
- 客户:访问代理对象的人!
代码步骤:
接口
代码语言:javascript复制//房子public interface Rent { public void rent();}
真实角色
代码语言:javascript复制//房东public class Host implements Rent {
@Override public void rent() {
System.out.println("房东要出租房子!");
}}
代理角色
代码语言:javascript复制//代理public class Proxy implements Rent{ private Host host; public Proxy() { } public Proxy(Host host) { this.host = host; } @Override public void rent() { seeHouse(); host.rent(); hetong(); fare(); } //看房 public void seeHouse(){ System.out.println("中介带你看房"); } //签合同 public void hetong(){ System.out.println("签合同"); } //收中介费 public void fare(){ System.out.println("收中介费"); }}
客户端访问代理角色
代码语言:javascript复制public class Client { public static void main(String[] args) { //房东要租房子 Host host = new Host(); //代理,中介帮房东租房子,但是代理角色会加一些附属操作 Proxy proxy = new Proxy(host); //你不用面对房东,直接找中介租房即可 proxy.rent(); }}
代理模式的好处:
- 可以使真实角色的操作更加纯粹,不用去关注一些公共业务
- 公共业务就交给了代理角色,实现了业务的分工
- 公共业务发生扩展的时候,方便集中管理
缺点:
- 一个真实角色就会产生一个代理角色,代码量会翻倍,开发效率会变低
10.2 加深理解
10.3动态代理
- 动态代理和静态代理角色一样
- 动态代理的代理类是动态生成的,不是我们直接写好的
- 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
- 基于接口—-JDK动态代理
- 基于类:cglib
- java字节码实现 : Javassist
需要了解两个类:Proxy,InvocationHandler
InvocationHandler
- 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务
- 公共也就交给代理角色!实现了业务的分工
- 公共业务发生扩展的时候,方便集中管理
- 一个动态代理类代理的是一个接口,一般就是对应的一类业务
- 一个动态代理类可以代理多个类,只要是实现了同一个接口即可
11.AOP
什么是AOP
AOP意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术,AOP是OOP的延续,是软件开发中的一个热点,也是String框架中的一个重要内容,是函数式编程的一种衍生范型,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发效率。
术语:
- Aspect:切面,表示增强的功能,就是一推代码,完成某一个功能,非业务功能,常见的切面功能有日志,事务,统计信息,参数检查,权限验证
- JoinPoint:链接点,连接业务方法和切面的位置,就某类中的业务的方法
- 目标对象:给哪个类的方法增加功能,这个类就是目标对象
切面有关的三要素:
- 切面的功能代码,切面干什么
- 切面的执行位置,使用Pointcut表示切面执行的位置
- 切面的执行时间,使用Advice表示时间,在目标方法之前,还是目标方法之后
Aop的实现
aop是一个规范,是动态的一个规范化,一个标准
aop的技术实现框架:
- spring:Spring在内部实现了aop的规范,能做了aop的工作
- 我们项目开发中很少使用Spring的aop实现,因为spring的aop比较笨重
- AspectJ:一个开源的专门处理Aop的框架,Spring框架中集成了aspectj框架,通过spring就能使用aspectj的功能
- 使用xml的配置文件:配置全局事务
- 使用注解,我们在项目中要做aop功能,一般都用注解,aspectj有五个注解
学习Aspectj框架的使用:
- 切面的执行时间,这个执行时间在规范中叫做Advice(增强)
在aspectj框架中使用注解表示的,也可以使用xml配置文件中的标签
- @Before
- @AfterReturning
- @Around
- @AfterThrowing
- @After
- 表示切面执行的位置,使用的是切入点表达式