Spring是什么?
- 学习之前 自己在idea中新建一个md文档 (记录 ——xml依赖 记录——注解)
- Web开发中的一阵春风,解决任何java应用开发
- 2002年 interface21 Spring前身。2004年Spring出现
- 概念:一个开源免费的、轻量级的控制反转和面向切面的框架
优点:
- 1、开源免费
- 2、轻量级(只需要加依赖就行),非侵入性(不用更改业务源代码)
- 3、控制反转和面向切面
- 4、支持对事务的操作,对框架整合的支持
缺点:
- 体系庞大。配置大多。
IOC:控制反转
ioc是一种编程思想:将主动编程变为被动接受。 对象的 交给Spring创建 管理 装配。
控制:谁来控制对象的创建,传统的程序的对象时由程序本身来创建,使用Spring时,对象由Spring创建。
反转:程序本身不创建对象,而变成被动接受对象。
依赖注入:使用set方法注入属性值
Spring怎么创建对象
1、XML文件(Bean标签)
2、注解 (5个注解)
Spring 依赖注入:
1、xml (bean标签的其他属性 两种 set 构造器注入 )
2、继基于接口的注解注入
问题:有几种注入方式?3种先创建Maven工程,在配置文件中加入依赖。Spring——web MVC 使用MVC是一次性的加载多个依赖。 (后面项目可以使用创建spring工程)
1、XML文件的方式
怎们创建对象????????????
*****实现过程——反射: 找XML文件,拆解XML文件,反射创建,交给Spring容器管理。
官方的创建对象学习地址:
Spring 配置包含容器必须管理的至少一个,通常是多个 bean 定义。基于 XML 的配置元数据将这些 bean 配置为
<bean/>
顶级元素内的<beans/>
元素。自定义XML文件将以下代码赋值进入,将官方定义的<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" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <!-- more bean definitions go here --> </beans>
java代码 main方法中 获取配置文件的类对象。
作用:加载Spring xml文件中的Bean 可以写多个xml文件。
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
- 自定义对象时需要有自己的类,spring中也有自己的一些对象。
自定义类 public class user { private String username; user(){ username=“nihao” } //get set 方法 }
- 创建对象默认无参构造方法创建(官方还有其他方法创建可以去官方网址参考) 类属性赋值必须有 set方法
- 有参构造创建对象时:根据参数顺序创建、根据参数类型创建、根据参数名称创建
- set方法注入下面说
对象创建的时机:?????????获取 (xml文件)上下文的时候
获取对象:getBean()
xml文件的配置 标签:<alias/>别名
<alias name="fromName" alias="toName"/> name:bean的id alias:bean的别名 获取的时候用
<bean> 创建对象
<bean id="exampleBean" class="examples.ExampleBean"/ name=" a, b ,c" scope=""> name :也是别名 可以写多个 scope:作用域:默认单例 更多属性 自己查看
<import>导入其他xml resources里面写路径。
依赖注入:
DI 依赖注入是IOC 的实现 办法。
依赖:创建对象的过程依赖于 Spring容器
注入:对象的属性 通过Spring容器注入。
官方解释:
依赖 对象的属性
注入:创建对象时将属性注入赋值
构造器注入(上面已说)、set注入、拓展注入
set注入
被创建对象时注入属性的类————
—— Set注入根据属性名注入
普通值注入
<bean id="xiaoming" class="cn.zhangyongqi.user"> <property name="zhang" value="good"> </bean> 根据属性名字 注入。
bean注入 Address自定义的类型 下面赋值给Address创建对象 ,上面将对象注入给Student类的属性。——(自动装配的前身 现在是主动装配,)
bean注入 数组类型
bean注入 list类型
bean注入 Map类型
bean注入 Set类型
bean null值注入
bean proerties类型注入
拓展注入:cp命名空间注入
- p对应set
- c对应构造器
p 先导入 p命名空间的依赖项 property<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" p命名的依赖性 xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean name="classic" class="com.example.ExampleBean"> <property name="email" value="someone@somewhere.com"/> </bean> 两种注入的属性值 效果相同 <bean name="p-namespace" class="com.example.ExampleBean" p:email="someone@somewhere.com"/> </beans>
c 命名空间,先导入依赖项 c:会出现构造器参数出现 constructor
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" c命名空间的依赖项 xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="beanTwo" class="x.y.ThingTwo"/> <bean id="beanThree" class="x.y.ThingThree"/> <!-- traditional declaration with optional argument names --> <bean id="beanOne" class="x.y.ThingOne"> <constructor-arg name="thingTwo" ref="beanTwo"/> <constructor-arg name="thingThree" ref="beanThree"/> <constructor-arg name="email" value="something@somewhere.com"/> </bean> 两种注入方法效果相同 下面更方便。 <!-- c-namespace declaration with argument names --> <bean id="beanOne" class="x.y.ThingOne" c:thingTwo-ref="beanTwo" c:thingThree-ref="beanThree" c:email="something@somewhere.com"/> </beans>
作用域:Scope
(作用域是什么意思,单例原型 是什么 23种设计模式【狂神说Java】单例模式-23种设计模式系列_哔哩哔哩_bilibili)
*****
默认单例的,怎么取都只有一个相同对象。
<bean id="accountService" class="com.something.DefaultAccountService"/> <!-- the following is equivalent, though redundant (singleton scope is the default) --> <bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/> 加标签 scope="singleton"
原型的:
<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/> 原型 scope="prototype"
其余的在web应用里面使用。.....(先不聊了)
基于XML的自动装配
- 自动注入是Spring满足bean依赖的一中方式
- Spring会在上下文中寻找,并给bean装配属性
Spring中有三种装配模式
- xml中的显示配置 、(显示是直接给值上面的set注入 隐式是去找值)
- java中的显示配置 (直接给值)
- 隐式的自动装配bean配置 *****
xml的隐式装配***************************byName —— byTypespring加载3个类 得到3个对象 人 狗 猫 人类中有猫和狗的属性 下面主动为属性注入了。
——byName 根据Spring容器中的bean ID去找 和需要装配的属性(set方法注入)的名称。
——byType 根据Spring容器中的bean ID去找 和需要装配属性类型。
使用注解实现自动装配
使用注解须知导入约束
配置注解支持
<?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>
@AutoWired 默认byType 类型注入 找不到根据byName(bean id) (required 两个值 true自动装配 false放弃自动装配 )
@Resource 根据名称再根据类型
当需要创建某个类的对象到Spring容器里面时,给对象的属性赋值时将@AutoWired注解在类属性上。也可用在set方法上 一样的赋值。
用在属性上时可以没有Set方法。(反射 暴力注入) ——(题外话:Lombok注解可以不写set get方法)
@Qualifier(value=“bean的id名”) 一般写在@AutoWired的下面 表示类型找不到按beanid找。
@Nullable 注解 用在构造器注入时 可以允许null
2、使用注解(装配对象)实现开发:
Spring4之后使用注解
****配置bean需要 导aop的包 上面导依赖时已经包含了。
****需要注解支持的标签
——使用XML扫描。
加标签扫描根包下的bean 带了组件注解的类才能扫描。 <context:component-scan base-package="cn.te.zhang.entity">
组件注解 加在类上。
- @Componet:组件的意思——通用加载bean的注解
- @Service:用在业务类上
- @Controller:控制器上
- @Repository: 数据存取类 (DAO)
——使用 纯java类 扫描配置对象。
- 另外后面会用到不用XML配置,在类上使用@Configuration 表示他是配置类。
- 两种实现形式。 将类作为容器 将包作为容器
- 将类作为容器:加了@bean注解的方法的返回值就是对象 @bean注解可以更改bean的默认名字(方法名),获取bean时就是根据方法名去掉get 获取。前提是User类加了组件注解 类比xml返回值为bean标签的class 属性 方法名相当于 id属性。
- 将包作为容器: 配置类就是当加载此类时 ,工作将包下的加了注解主键的类放到容器里面。
@ComponentScan(根包:要加载进Spring容器里面的) ,加载配置类时就会扫描加载根包下的类。@Configuration 配置类注解 @ComponentScan({"cn.tedu.spring","java"}) 扫描注解 @import(类/包) 导入其他配置类注解 public class xxxconfig(){ }
- 配置类 一般命名使用xxx+config
AOP:面向切面编程
先讲代理模式:(23设计模式)AOP的底层就是代理模式的实现
什么是代理模式? 需要某些代理对象帮助完成某些事。
分类
静态代理:一个代理对象对应一个真实对象
动态代理:
静态代理
例子详解:
角色分析:
抽象角色:(接口或抽象类实现)这里为出租行为
真实对象:房东 被代理的角色
代理对象:代理真实对象的一些操作,再加自己的附属操作
客户: 访问代理对象的人
代码实现:
抽象角色 出租
真实角色 房东 被代理的角色 要实现抽象对象 出租行为
代理角色:中介 也要实现抽象对象 重写出租行为时 使用房东 的出租行为。
客户: 用户租房的人。 为什么直接new 了房东 ?演示 ,, 实际可用反射注入到代理的构造方法中
代理对象脱离 真实对象 可以自己添加行为 (service 层的行为 )不用改变真实对象
还是调用 rent方法时 结果不同
优点:可以使真实角色更加存粹
公共业务交给代理实现
公共业务发生扩展更加方便管理
缺点:
一个真实对象需要new一个代理对象
动态代理:
1、与静态代理的角色一样
2、代理关系不是写死的 一对一的,根据传入改变,代理角色动态生成
3、分类:
基于接口 : jdk
基于类 : cglib(了解jvm比较麻烦)
字节码: javasist
需要了解两个类(为生成代理对象执行方法。)
Proxy 代理对象
InvocationHandle 调用处理的接口
InvocationHandle 源码说明文档
invoke方法 (代理对象调用真实对象时会利用反射机制调用此方法。)
参数:[ 代理的对象 方法对象 (代理对象执行的方法) 方法参数 (前面方法的参数,因为有重载 ,根据参数判定执行哪一个) ] 反射实现。
Proxy 的源码说明文档
里面有一个静态方法可以生成代理对象(可以不强转 直接用Object接受)
参数: (真实角色的类路径 抽象角色(出租行为) 执行invoke方法的对象)
代码实现动态代理:
下面为生成代理对象和执行方法的工具类 为什么写? 将方法封装。不然每次使用前得
用匿名内部类创建一个执行invoke方法的对象(实现InvocationHandle接口,等下传到Proxy静态方法的参数里面)。
使用Proxy静态方法得到代理对象,代理对象会使用匿名内部类的重写的invoke方法
创建一个 工具类
上述静态代理的 出租rent接口 和真实角色 房东HOst不变(那两个类或接口不变)
客户 用户、
好处:
包含静态代理的好处
一个动态代理类可以代理 一个接口(一般 表示某些行为业务)
一个动态代理类可以代理多个实现接口的类。(可以得到多个房东)
AOP:面向切面编程
Spring 的关键组件之一是 AOP 框架。虽然 Spring IoC 容器不依赖 AOP(这意味着如果您不想使用 AOP,则无需使用 AOP),AOP 补充了 Spring IoC 以提供非常强大的中间件解决方案。
面向切面编程;对oop面向对象编程的补充。通过预编译的方式和运行期间动态代理 实现程序功能的统一维护的一种技术
函数式编程的衍生范型,
aop可使业务逻辑各个部分进行隔离,从而使得业务逻辑之间耦合度降低,提高程序可复用性,同时提高开发效率。
pom文件加依赖
方式1
使用Spring接口 实现
准备抽象角色(行为)
真实角色(房东)
增强方法 切入方法
执行增强方法 在方法执行前重写before方法 参数对应动态代理的invoke方法参数
Method 代理对象执行的方法args 方法参数
Object 代理对象(应该说真实角色对象 )
执行增强方法 在方法执行后
参数跟上述一样
配置xml
导入AOPjar包
将 这几个类导入 spring容器、配置aop。 需要切入点 切入方法
测试
获取xml、文件 、(得到Spring容器)
得到代理对象(相当于一个没有类名的对象 只是实现了接口)(已经不是接口了 )(需要向上造型 变成接口对象)
执行方法
方式2 使用自定义类作为切面实现
将类作为切面
设置xml文件 aop 上一种方式的bean不变
diy类为切面 可以在 切入点(方法)切入方法。
测试
比较简单,但是可操作性没上面的高 ,因为上面的方法参数多。
使用注解实现:继续使用类做切面(只是将xml文件配置换为注解)
和上面一样自定义类 做切面切点前 切点后 切点环绕
切点环绕方法执行的时机 参数jp为执行的切入点
配置xml 将自定义类注册为Spring对象、开启注解支持测试和刚刚的一样
注解的缺点:需要多次配置切点 也是一个好处。
3、整合Mybatis
步骤:
1、导包: junit 、 mybatis 、 mysql 、 spring、 aop织入、
spring jdbc mybatis—spring(中文文档 还有 mybatis-spring-boot-start) (和谁整合杠谁)
2、编写配置文件
3、测试
回忆mybatis——————编写实体类
编写核心配置文件
编写mapper接口
编写mapper.xml
测试
核心配置文件——
开发环境
type 哪种管理
value 驱动
url连接到哪个库、时间 、 安全连接、编码、
连接数据库 : 测试
mybatis——spring整合
spring中声明事务:业务一般都需要声明事务。
mybatis-spring –事务管理的官网文档
MyBatis-Spring 借助了 Spring 中的DataSourceTransactionManager
来实现事务管理。
声明式事务:AOP 横切进去的
编程式事务:需要在代码中声明事务的管理
编程式:
public class UserService {
private final PlatformTransactionManager transactionManager;
public UserService(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public void createUser() {
TransactionStatus txStatus =
transactionManager.getTransaction(new DefaultTransactionDefinition());
try {
userMapper.insertUser(user);
} catch (Exception e) {
transactionManager.rollback(txStatus);
throw e;
}
transactionManager.commit(txStatus);
}
}
声明式事务:———————————————————————————————————
一、配置事务管理器的bean DataSourceTransactionManager
二、导入TX 约束 tx:advice配置事务通知(对应下面的配置注解支持)
transaction-manager 使用的事务管理器
tx:attribute 配置使用事务的方法
tx:method 方法名 单个方法所有方法
propagation:事务的传播级别 7种
三、AOP织入:
aop:config 配置切入
配置切入点 执行位置 包下的类下的所有方法(..)代表参数
aop:advice 配置事务 pointcut-ref 配置切入点
配置事务管理代码
传播级别:
———————————————————————————————
注解支持
基于注解方式来进行声明式事务的操作会更加简单,在实际开发中我们也会用的比较多,我们基于以上案例继续完成
@Transactional 注解只应用到 public 修饰的方法上,在 protected、private 修饰的方法上都不会起作用
1)配置事务管理器(同上1) <!-- 1.配置事务的管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 指定要对哪个数据库进行事务操作 --> <property name="dataSource" ref="dataSource"></property> </bean> 1 2 3 4 5 2)注释掉事务的其他配置,开启事务注解 <!-- 2.开启事务的注解 --> <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven> 1 2 完成之后的配置文件问: <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" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!--指定注解扫描包路径--> <context:component-scan base-package="com.oak"/> <!-- 导入资源文件 --> <context:property-placeholder location="classpath:dbutil.properties"/> <!-- 配置dbcp连接池参数 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${user}" /> <property name="password" value="${password}" /> <!-- 连接池启动时的初始值 --> <property name="initialSize" value="${initsize}" /> <!-- 连接池的最大值 --> <property name="maxActive" value="${maxsize}" /> <!-- 最大空闲值。当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 --> <property name="maxIdle" value="${maxIdle}" /> <!-- 最小空闲值。当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 --> <property name="minIdle" value="${minIdle}" /> </bean> <!-- 配置 Spring 的 jdbcTemplate --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 1.配置事务的管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 指定要对哪个数据库进行事务操作 --> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 2.开启事务的注解 --> <tx:annotation-driven transaction-manager="transactionManager"> </tx:annotation-driven> </beans>
spring boot 直接使用@Transactional注解就行。