Spring
1 、Spring
1.1 简介
- Spring理念:使现有的技术更加容易使用,本身是个大杂烩,整合了现有的技术框架 
- SSH ->Stucts2+Spring+Hibernate || SSM->SpringMVC+Spring+Mybatis 
- 下载方式: 
- 下载地址:repo.spring.io 
- github:GitHub - spring-projects/spring-framework: Spring Framework 
- Maven的依赖导入: - ` - org.springframework - spring-webmvc - 5.3.21 
 
1.2 优点
- spring是一个开源的免费的框架(容器) 
- Spring是一个轻量级的非入侵式的框架 
- 控制反转(IOC) 面向切面编程(AOP) 
- 支持事务的处理,对框架整合的支持 - 总结:Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架
1.3 组成

1.4扩展
现代化的Java开发

 构建一切-(SpringBoot)–>协调一切(Spring Cloud)—>连接一切(Spring Cloud Data Folw)
- Spring Boot- 快速开发的脚手架
- 基于SpringBoot可以快速的 开发单个微服务
- 约定大于配置
 
- SpringCloud- SpringCloud式基于SpringBoot实现的
 
因为大多数的公司使用SpringBoot快速开发,学习SpringBoot的前提就是学习Spring和SpringMVC
弊端:发展了太久之后,违背了原来的理念,配置十分繁琐,“配置地狱”
2、IOC的推导
- UserDao接口 
- UserDaoImpl接口的实现类 
- UserService业务接口 
- UserServiceImpl业务实现类 - 在之前的业务中用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改源代码,如果程序代码量十分庞大修改一次的成本代价十分昂贵 - 我们去用一个Set接口来实现 - 1 
 2
 3
 4
 5- private UserDao userDao; 
 //利用Set进行动态实现值的注入!
 public void setUserDao(UserDao userDao){
 this.userDao=userDao;
 }- 之前,程序是主动创建对象!控制权在程序员手中
- 使用了Set注入后,程序不再具有主动性,而是变成被动的接收对象
 - 这种思想,从本质上解决了问题,我们程序员不用再去管理对象的创建了,系统的耦合性大大降低,可以更加专注的在业务实现上  


3、HelloSpring
4、IOC创建对象的方式、
- 使用无参构造创建对象(默认) 
- 假设要使用有参构造方法 - 下标赋值   <constructor-arg index="下表数" value="下标值"/>
- 通过类型创建(不推荐):<constructor-arg type="java.lang.String" value="张锋学JAVA"/>
- 直接通过参数名来设置:
 - 1 
 2
 3- <bean id="User" class="com.zhang.pojo.User"> 
 <constructor-arg name="name" value="张锋学JAVA"/>
 </bean>
- 下标赋值   
 总结:在配置文件加载的时候,容器中的管理对象就已经开始初始化了
5、Spring配置
- 别名- 1 
 2- <!--如果添加了别名可以用别名来获取对象--> 
 <alias name="User" alias="userasd"/>
- Bean的配置- 1 
 2
 3
 4
 5
 6
 7
 8- <!-- 
 id:bean的唯一标识符,也就是我们所说的对象名
 class:bean对象对应的全限定名:包名+类型
 name:也是别名
 -->
 <bean id="userF" class="com.zhang.pojo.User" name="user3,u3">
 <constructor-arg value="zf牛逼"/>
 </bean>
- import- 一般运用于团队开发,可以将多个配置文件合并成一个 - 假设,现在一个项目由多人开发,这三个人复制不同类的开发,不同的类需要注册在不同的bean’中,我们可以利用,import将所有人的bean.xml合并成一个总的,最后使用的时候直接配置总的就好 - 张三 
- 李四 
- 王五 
- applicationContext.xml - 1 
 2
 3
 4
 5- <import resource="beans.xml1"/> 
 <import resource="beans.xml2"/>
 <import resource="beans.xml3"/>
 
6、依赖注入
- 构造器注入- 前面说过了 
- Set方式注入- 【环境搭建】 -  1.复杂环境 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13- package com.zhang.pojo; 
 public class Address {
 private String address;
 public String getAddress() {
 return address;
 }
 public void setAddress(String address) {
 this.address = address;
 }
 }-  2.真实测试对象 - 1 
 2
 3
 4
 5
 6
 7
 8
 9- public class Student { 
 private String name;
 private Address address;
 private String book[];
 private List<String> hobbys;
 private Map<String,String> card;
 private Set<String> games;
 private Properties info;
 private String wife;- 3.beans - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 <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="Student" class="com.zhang.pojo.Student">
 <property name="name" value="张锋"/>
 </bean>
 </beans>- 4,测试类 - 1 
 2
 3
 4
 5
 6
 7- public class Mytest { 
 public static void main(String[] args) {
 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
 Student student = (Student)context.getBean("Student");
 System.out.println(student.getAddress());
 }
 }- 普通注入
 - 1 
 2
 3
 4- <bean id="address" class="com.zhang.pojo.Address"/> 
 <bean id="Student" class="com.zhang.pojo.Student">
 <!--普通注入-->
 <property name="name" value="张锋"/>- 2.数组注入 - 1 
 2
 3
 4
 5
 6
 7
 8
 9- <!--数组--> 
 </property>
 <property name="book">
 <array>
 <value>红楼梦</value>
 <value>西游记</value>
 <value>水浒传</value>
 </array>
 </property>
 3.List注入
| 1 | <!--List注入--> | 
 4.set注入
| 1 | <property name="games"> | 
5 空值注入
| 1 | <property name="wife"> | 
6 properties注入
| 1 | <!--properties注入--> | 
3.拓展注入
4.bean的作用域
① singleton
使用该属性定义Bean时,IOC容器仅创建一个Bean实例,IOC容器每次返回的是同一个Bean实例。
② prototype
使用该属性定义Bean时,IOC容器可以创建多个Bean实例,每次返回的都是一个新的实例。
③ request
该属性仅对HTTP请求产生作用,使用该属性定义Bean时,每次HTTP请求都会创建一个新的Bean,适用于WebApplicationContext环境。
④ session
该属性仅用于HTTP Session,同一个Session共享一个Bean实例。不同Session使用不同的实例。
⑤ global-session
该属性仅用于HTTP Session,同session作用域不同的是,所有的Session共享一个Bean实例。
5.bean的自动装配
- 环境搭建:一个人有两个宠物 
- byName的自动装配: - 1 
 2
 3
 4
 5- <bean id="cat" class="com.zhang.pojo.cat"/> 
 <bean id="dog" class="com.zhang.pojo.dog"/>
 <bean id="people" class="com.zhang.pojo.people" autowire="byName">
 <property name="name" value="张锋"/>
 </bean>- 3.byType的自动装配: - 1 
 2
 3
 4
 5
 6- <!--byName:会自动再容器上下文中查找,和自己对象类型后面的值对应的bean--> 
 <bean id="cat1111" class="com.zhang.pojo.cat"/>
 <bean id="dog1111" class="com.zhang.pojo.dog"/>
 <bean id="people" class="com.zhang.pojo.people" autowire="byType">
 <property name="name" value="张锋"/>
 </bean>- 小结
- byName:需要保证所有的bean的id唯一,并且这个bean和需要自动注入的属性set方法的值一致 
- byType:需要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性类型一致 - 6.使用注解实现自动装配- @Autowired:直接在属性上使用即可,也可以在set方法上使用,使用Autowired我们可以不用编写Set方法了,前提是你这个自动装配的属性IOC(Spring)容器中存在,且符合名字byName - 测试代码: - 1 
 2
 3
 4
 5- private String name; 
 //如果Autowired后面的required属性为false,说明这个对象可以null,否则不允许为空
 private cat cat;
 private dog dog;- 如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,我们可以使用@Qualfier(value=”xxx”)去配置@Autowired的使用,指定一个唯一的bean对象注入 - 测试代码: - 1 
 2
 3
 4
 5
 6
 7- private String name; 
 private cat cat;
 private dog dog;
7、Spring注解开发
1.自动装配配置
@autowired :通过类型和名字进行自动装配,如果autowired不能唯一自动装配上属性,则需要通过@Qualifier(value=”xxx”)
@Nullable:字段标记了这个注解,说明这个字段可以是Null
@Resource 通过名字类型自动装配
@Component:组件,放在类上,说明这个类被Spring管理了,就是bean
2.属性如何注入
| 1 | //组件 | 
3.衍生注解
@Component有几个衍生注解,我们在Web开发中,会按照MVC三层架构进行分层
- dao [@Repository ]
- service[@Sercive]
- controller[ ]
4.作用域
| 1 | //组件 | 
5.小结
XML与注解
- xml更加万能,适用于更多场合,维护简单方便
- 注解不是自己的类用不了,维护相对复杂
- XML用来管理bean
- 注解只用来管理属性的注入
8、代理模式
为何要学习代理模式:代理模式是SpringAOP的底层
代理的分类:静态代理和动态代理
1.静态代理
- 抽象角色:一般使用接口和抽象类来解决
- 真实角色:被代理角色
- 代理角色:代理真实后,我们会做一些附属操作
- 客户:访问代理的人
2.动态代理
动态代理和静态代理的角色一样
动态代理的代理类是动态生成的,不是我们直接写好的
动态代理分为两大类:基于接口的动态代理,基于类的动态代理
- 基于接口的动态代理:JDK的动态代理
- 基于类的动态代理:cglib
- JAVA字节码实现:javassist
了解两个类:Proxy 代理 ,invocationHandler:调用处理程序
- 动态代理的基本代码 - ProxyInvocationHandler类的代码: - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24- import java.lang.reflect.Proxy; 
 //用这个类自动生成代理类
 public class ProxyInvocationHandler implements InvocationHandler {
 private Object object;
 public void SetTarget(Object object){
 this.object=object;
 }
 public Object getProxy( ){
 return Proxy.newProxyInstance(this.getClass().getClassLoader(),object.getClass().getInterfaces(),this );
 }
 
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 log(method.getName());
 Object invoke = method.invoke(object, args);
 return invoke;
 }
 public void log(String msg){
 System.out.println("调用了一个"+msg+"方法");
 }
 }
应用:
| 1 | public class Client { | 
3、AOP(面向切面编程)
- 使用Spring实现AOP -  xml中配置文件头: - 1 
 2
 3
 4
 5
 6
 7
 8
 <beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 https://www.springframework.org/schema/beans/spring-beans.xsd
 http://www.springframework.org/schema/aop
 https://www.springframework.org/schema/aop/spring-aop.xsd">-  方法1:原生的Spring API接口 - 以创建日志为例: 两个日志类为:Log和AfterLog - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11- package com.zhang.demo1; 
 import org.springframework.aop.MethodBeforeAdvice;
 import java.lang.reflect.Method;
 public class log implements MethodBeforeAdvice {
 //method要执行的目标的对象方法
 //Object:参数
 
 public void before(Method method, Object[] args, Object target) throws Throwable {
 System.out.println(target.getClass().getName()+"的"+method.getName()+"的方法被执行了");
 }
 }
 
 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14- package com.zhang.demo1; 
 import org.springframework.aop.AfterAdvice;
 import org.springframework.aop.AfterReturningAdvice;
 import java.lang.reflect.Method;
 public class AfterLog implements AfterReturningAdvice {
 
 public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
 System.out.println("执行了"+method.getName()+"结果为"+returnValue);
 }
 }
 ApplicationContext.xml
| 1 | 
 | 
测试类:
| 1 | import com.zhang.demo1.UserService; | 
输出结果

第二种方法:自定义切点法
 自定义切点类 DiyPointCut
| 1 | package com.zhang.demo1; | 
配置文件:ApplicationContext.xml
| 1 | 
 | 
 输出结果:

 AOP原理如图:

9、Mybatis-Spring
 项目结构

- 编写数据源配置 - 1 
 2
 3
 4
 5
 6- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
 <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
 <property name="url" value="jdbc:mysql://localhost:3306/user?useSSL=false&allowPublicKeyRetrieval=true"/>
 <property name="username" value="root"/>
 <property name="password" value="root"/>
 </bean>
- sqlSessionFactory 
| 1 | <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> | 
- sqlSessionTemplate
| 1 | <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> | 
- 需要给接口加实现类
| 1 | public class UserMapperImp implements UserMapper{ | 
10、声明式事务
1、回顾事务
-  把一组业务当成一个业务来做,要么都成功,要么都失败!
- 十五在项目开发中十分重要,设一道数据一致性的问题,不能马虎
- 确保完整性和一致性
事务的ACID原则:
- 原子性
- 一致性
- 隔离性
 多个业务放到同一个资源防止数据破坏
- 持久性
 事务一旦提交,无论发生什么问题,结果都不会在被影响,被持久化写道存储器中



