1、Spring

1.1、简介

  • 2002,首次推出Spring框架的雏形,interface21框架

  • 2004.3.24发布了1.0

  • Rod Johnson Spring Framework的创始人

  • SSH Struct2 + Spring + Hibernate

  • SSM SpringMVC + Spring + Mybatis

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-webmvc</artifactId>
  5. <version>5.0.4.RELEASE</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.springframework</groupId>
  9. <artifactId>spring-jdbc</artifactId>
  10. <version>5.0.3.RELEASE</version>
  11. </dependency>
  12. </dependencies>

1.2、优点

  • Spring是一个开源的免费的框架(容器)
  • Spring是一个轻量级、非入侵的框架
  • 控制反转IOC、面向切面编程AOP
  • 支持事务的处理,对框架整合的支持

Spring是一个轻量级的控制反转、面向切面(AOP)编程的框架

1.3、组成(面试角度)

  • 别只说IOC和AOP

Spring - 图1

  1. Spring Core
    Core模块是Spring的核心类库,Spring的所有功能都依赖于该类库,Core主要实现IOC功能,Spring的所有功能都是借助IOC实现的。
    1. IOC的基本概念是:不创建对象,但是描述创建它们的方式。在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务。容器负责将这些联系在一起。
  1. AOP
    AOP模块是Spring的AOP库,提供了AOP(拦截器)机制,并提供常用的拦截器,供用户自定义和配置。 
    AOP是OOP的延续,是(Aspect Oriented Programming)的缩写,意思是面向切面(方面)编程。

  2. ORM

Spring 的ORM模块提供对常用的ORM框架的管理和辅助支持,Spring支持常用的Hibernate,ibtas,jdao等框架的支持

Spring本身并不对ORM进行实现,仅对常见的ORM框架进行封装,并对其进行管理。

  1. DAO
    Spring 提供对JDBC的支持,对JDBC进行封装,允许JDBC使用Spring资源,并能统一管理JDBC事物,并不对JDBC进行实现。

  2. WEB
    WEB模块提供对常见框架如Struts1,WEBWORK(Struts 2),JSF的支持,Spring能够管理这些框架,将Spring的资源注入给框架,也能在这些框架的前后插入拦截器。

  3. Context模块
    Context模块提供框架式的Bean访问方式,其他程序可以通过Context访问Spring的Bean资源,相当于资源注入。

  4. MVC模块
    WEB MVC模块为Spring提供了一套轻量级的MVC实现,在Spring的开发中,我们既可以用Struts也可以用Spring自己的MVC框架,相对于Struts,Spring自己的MVC框架更加简洁和方便。

1.4、拓展

Spring Boot —- Spring Cloud —- Spring Cloud Data Flow

构建一切 —- 协调一切 —- 连接一切

2、HelloSpring

1、构建项目

2、导入依赖

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-webmvc</artifactId>
  5. <version>5.0.4.RELEASE</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.springframework</groupId>
  9. <artifactId>spring-jdbc</artifactId>
  10. <version>5.0.3.RELEASE</version>
  11. </dependency>
  12. </dependencies>

3、编写代码

  • 创建一个实体类 com.zmy.pojo.Hello

    • 属性
    • 无参构造
    • getset方法
    • toString
  • 编写配置文件 ApplicationContext.xml (beans.xml)
    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://www.springframework.org/schema/beans
    5. https://www.springframework.org/schema/beans/spring-beans.xsd">
    6. <!--使用Spring来创建对象,这些成为bean-->
    7. <bean id = "hello" class="com.zmy.pojo.Hello">
    8. <property name="hello" value="Hello Spring"/>
    9. </bean>
    10. </beans>
  • 测试
    1. //获取上下文对象
    2. ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    3. //我们的对象都在Spring中管理了,我们要是用,直接去里面取出来就可以 getBean
    4. Hello hello = (Hello) context.getBean("hello");
    5. System.out.println(hello.toString());
  • 思考

    • Hello是谁创建的
    • Hello对象的属性是怎么设置的
  • 控制:谁来控制对象的创建,传统是new程序本身控制,Spring后对象是由Spring创建的

  • 反转:程序本身不需要创建对象,而变成被动的接收
  • 依赖注入:就是利用set方法进行注入的

3、IOC创建对象的方式

  1. 使用无参构造创建对象,默认!

  2. 假设使用有参构造方法创建对象

    1. 下标赋值
      1. <bean id="exampleBean" class="examples.ExampleBean">
      2. <constructor-arg index="0" value="7500000"/>
      3. <constructor-arg index="1" value="42"/>
      4. </bean>
  1. 参数类型(不建议)(属性相同比较鸡肋)
    1. <bean id="exampleBean" class="examples.ExampleBean">
    2. <constructor-arg type="int" value="7500000"/>
    3. <constructor-arg type="java.lang.String" value="42"/>
    4. </bean>
  1. 参数名为设置
    1. <bean id="user" class="com.zmy.pojo.User">
    2. <constructor-arg name="name" value="张三"/>
    3. <constructor-arg name="password" value="法外狂徒"/>
    4. </bean>

总结:在配置文件加载的时候,容器中的管理对象就已经开始初始化了!

4、Spring配置

4.1、别名

  1. <bean id="user" class="com.zmy.pojo.User">
  2. <constructor-arg name="name" value="张三"/>
  3. <constructor-arg name="password" value="法外狂徒"/>
  4. </bean>
  5. <alias name="user" alias="user2"/>

4.2 、Bean的配置

  1. <!--
  2. id:bean的唯一标识符,也就相当于我们的对象名
  3. class:bean对象所对应的全限定类名:包名+类名
  4. name:也是别名的意思 name比alias高级,它可以取多个别名
  5. -->
  6. <bean id="user" class="com.zmy.pojo.User" name="user3 u2,u3;u4">
  7. <constructor-arg name="name" value="张三"/>
  8. <constructor-arg name="password" value="法外狂徒"/>
  9. </bean>
  10. <alias name="user" alias="user2"/>

4.3、import

import可以将多个配置文件,导入合并为一个。将所有人的beans.xml合并

5、依赖注入DI

5.1、构造器注入

前面

5.2、set方法注入【重点】

  • 依赖注入:set注入

    • 依赖:bean对象的创建依赖于容器
    • 注入:bean对象的所有属性,由容器来注入

【环境搭建】

  1. 复杂类型
    1. public class Address {
    2. private String name;
    3. public String getName() {
    4. return name;
    5. }
    6. public void setName(String name) {
    7. this.name = name;
    8. }
    9. }
  1. 真实测试对象
    1. public class Student {
    2. private String name;
    3. private Address address;
    4. private String[] books;
    5. private List<String> hobbys;
    6. private Map<String ,String> card;
    7. private String wife; //空指针
    8. private Properties info; //配置类
    9. }
  1. beans.xml
    1. <bean id="address" class="com.zmy.pojo.Address">
    2. <property name="name" value="唐山"/>
    3. </bean>
    4. <bean id="card" class="com.zmy.pojo.Card">
    5. <property name="num" value="1313"/>
    6. </bean>
    7. <bean id = "student" class="com.zmy.pojo.Student">
    8. <!--普通值注入,value-->
    9. <property name="name" value="赵明洋"/>
    10. <!--Bean注入,ref-->
    11. <property name="address" ref="address"/>
    12. <!--数组注入,array-->
    13. <property name="books">
    14. <array>
    15. <value>红楼梦</value>
    16. <value>西游记</value>
    17. <value>三国演义</value>
    18. <value>水浒传</value>
    19. </array>
    20. </property>
    21. <!--List注入,list-->
    22. <property name="hobbys">
    23. <list>
    24. <value>听歌</value>
    25. <value>看电影</value>
    26. <value>敲代码</value>
    27. </list>
    28. </property>
    29. <!--map注入,map-->
    30. <property name="card">
    31. <map>
    32. <!--<entry key="建设银行" value="110"/>-->
    33. <entry key="银行卡" value-ref="card"/>
    34. </map>
    35. </property>
    36. <!--properties注入-->
    37. <property name="info">
    38. <props>
    39. <prop key="driver">1120191549</prop>
    40. <prop key="url"></prop>
    41. <prop key="username"></prop>
    42. <prop key="password"></prop>
    43. </props>
    44. </property>
    45. <!--空值注入-->
    46. <property name="wife">
    47. <null/>
    48. </property>
    49. </bean>
  1. 测试类

    1. public class MyTest {
    2. public static void main(String[] args) {
    3. ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    4. Student student = (Student) context.getBean("student");
    5. System.out.println(student.toString());
    6. }
    7. }
  1. 完善注入信息

5.3、拓展注入

可以使用p命名空间和c命名空间进行注入(需要导入xml约束)

官方文档解释:https://docs.spring.io/spring-framework/docs/current/reference

6.4、Bean Scope

Spring - 图2

  1. 单例模式(Spring默认机制) user1==user2 true
    1. <bean id="address" class="com.zmy.pojo.Address" scope="singleton"/>
  1. 原型模式 user1==user2 false
    1. <bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>
  1. 其余的只能在web开发中使用到

6、Bean的自动装配Autowired

  • 自动装配是Spring满足bean依赖的一种方式
  • Spring会在上下文中自动寻找,并自动给bean装配属性

自动装配的方式

  1. 在xml中显示的配置
  2. 在java中显示配置
  3. 隐式 的自动自动装配bean【重要】

6.1、ByName

:会在上下文自动寻找和自己对象setXXX的XXX对应的beanID bean的id唯一

  1. public class User {
  2. private Cat cat;
  3. private Dog dog;
  4. }
  1. <bean id = "cat" class="com.zmy.pojo.Cat"/>
  2. <bean id = "dog" class="com.zmy.pojo.Dog"/>
  3. <bean id="user" class="com.zmy.pojo.User" autowire="byName"/>

小结:

当一个bean节点中带有autowired byName属性时

  1. 将查找其类中的所有set方法名,例如setCat,将获得cat
  2. 去Spring容器中寻找是否有字符串名称id的对象(bean节点的id属性,然后去找class属性)
  3. 如果有就注入,没有就空指针异常

6.2、ByType

:会在上下文自动寻找和自己对象属性相同的bean bean的类型唯一

  1. <bean id = "cat" class="com.zmy.pojo.Cat"/>
  2. <bean id = "dog" class="com.zmy.pojo.Dog"/>
  3. <bean id="user" class="com.zmy.pojo.User" autowire="byType"/>

小结:

带有autowired byType属性

  1. 将查找其类中的所有set方法名,例如setCat,将获得cat
  2. 去Spring容器中寻找是否有cat类型的对象(bean节点的Class属性)
  3. 如果有就注入,没有就空指针异常

6.3、总结

  • byName byType 本质上还是set方法注入

6.4、注解实现自动装配

  1. 导入约束:context约束

  2. 配置注解的支持 ```xml <?xml version=”1.0” encoding=”UTF-8”?>

  1. 3.
  2. **[@Autowired ](/Autowired ) ** (按类型自动装配)
  3. 测试:
  4. User类:
  5. ```java
  6. public class User {
  7. @Autowired
  8. private Cat cat;
  9. @Autowired
  10. private Dog dog;
  11. public Cat getCat() {
  12. return cat;
  13. }
  14. public Dog getDog() {
  15. return dog;
  16. }
  17. }

配置文件:

  1. <bean id = "cat" class="com.zmy.pojo.Cat"/>
  2. <bean id = "dog" class="com.zmy.pojo.Dog"/>
  3. <bean id="user" class="com.zmy.pojo.User"/>

测试成功!

  • 科普时间
  • @Autowired(required = false) false:可以为null true:不允许null
  • @Autowired @Qualifier(value = “cat111”) Qualifier:可以根据byName装配。不能单独使用
  • [ ] @Resource

    • 如有指定name属性,先按byName方式进行装配
    • 其次再进行默认的byName进行装配
    • 都失败,则按byType装配

小结:

  1. @Autowired和@Resource 都可以装配bean,都可以写在字段或者set方法上
  2. @Autowired(Spring规范)默认按照类型装配,默认情况下依赖对象必须存在
  3. @Resource(属于J2EE规范)^^^^^^^

7、使用注解开发

Spring4之后需要导入aop的包

使用注解开发需要导入context的约束,增加注解的支持

  1. bean的实现
    之前使用的是bean标签,实际中用的是注解

    1. 配置扫描那些包下的注解
      1. <!--指定要扫描的包,这个包下的注解就会生效-->
      2. <context:component-scan base-package="com.zmy.pojo"/>
  1. 在指定包下编写类,加入注解
    1. @Component
    2. public class User {
    3. @Resource
    4. private Cat cat;
    5. @Resource
    6. private Dog dog;
    7. public Cat getCat() {
    8. return cat;
    9. }
    10. public Dog getDog() {
    11. return dog;
    12. }
    13. }
  1. 属性如何注入

    • User类
      1. @Component
      2. public class User {
      3. // 相当于 <properties name = "", value = ""/>
      4. @Value("赵明洋")
      5. public String name;
      6. @Resource
      7. private Cat cat;
      8. public Cat getCat() {
      9. return cat;
      10. }
      11. }
  • 配置文件
    1. <!--指定要扫描的包,这个包下的注解就会生效-->
    2. <context:component-scan base-package="com.zmy"/>
  • 测试

    1. public class MyTest {
    2. public static void main(String[] args) {
    3. ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
    4. User user = context.getBean("user", User.class);
    5. System.out.println(user.name);
    6. user.getCat().shout();
    7. }
    8. }
  1. 衍生的注解
    @Component

    • @Controller :web层
    • @Service:service层
    • @Repository:dao层

都表示将类放入Spring容器中

  1. 自动装配置

  2. 作用域

    1. @scope(“单例”)
  1. 小结
  • xml与注解

    • xml更加万能,适用于任何场合,维护简单
    • 注解不是自己的类使用不了,维护相对复杂

8、使用java的方式配置Spring

不使用xml的配置了,全权交给Java去做

9、代理模式

为什么要学习代理模式? 因为这就是SpringAOP的底层 【SpringAOP SpringMVC】

代理模式分类:

  • 静态代理
  • 动态代理

9.1、静态代理

角色分析:

  • 抽象角色:一般会使用接口或者抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理真实角色后,一般会做一些附属操作
  • 客户:访问代理对象的人

代码步骤

  1. 接口:
    1. //租房
    2. public interface Rent {
    3. public void rent();
    4. }
  1. 真实角色(房东):
    1. public class Host implements Rent {
    2. public void rent() {
    3. System.out.println("房东要租房子");
    4. }
    5. }
  1. 代理角色(中介):
    1. public class Proxy {
    2. private Host host;
    3. public Proxy() {
    4. }
    5. public Proxy(Host host) {
    6. this.host = host;
    7. }
    8. //代理租房的主要功能及附属操作
    9. public void rent(){
    10. host.rent();
    11. seeHours();
    12. fee();
    13. }
    14. //看房子
    15. public void seeHours(){
    16. System.out.println("中介带你看房子");
    17. }
    18. //收费
    19. public void fee(){
    20. System.out.println("签订租赁合同");
    21. }
    22. }
  1. 客户:
    1. public class Client {
    2. public static void main(String[] args) {
    3. //房东要租房子
    4. Host host = new Host();
    5. //代理,中介帮房东租房子
    6. Proxy proxy = new Proxy(host);
    7. //直接找中介即可
    8. proxy.seeHours();
    9. }
    10. }

代理模式的好处:

  • 可以使真实的角色的操作更加纯粹,不用关注一些公共的业务
  • 公共也就交给代理角色,实现了业务的分工
  • 公共业务发生拓展的时候,方便集中管理

缺点:

  • 一个真实角色就会产生一个代理角色,代码量会翻倍

9.2、加深理解

  1. 抽象角色:

    1. public interface UserService {
    2. public void add();
    3. public void del();
    4. public void update();
    5. public void select();
    6. }
  1. 真实角色:

    1. public class UserServiceImpl implements UserService {
    2. public void add() {
    3. System.out.println("增加了一个用户");
    4. }
    5. public void del() {
    6. System.out.println("删除了一个用户");
    7. }
    8. }
  1. 代理角色:

    1. public class UserServiceProxy implements UserService{
    2. private UserServiceImpl userService;
    3. //set注入
    4. public void setUserService(UserServiceImpl userService) {
    5. this.userService = userService;
    6. }
    7. public void add() {
    8. log("add");
    9. System.out.println("增加了一个用户");
    10. }
    11. public void del() {
    12. log("del");
    13. System.out.println("删除了一个用户");
    14. }
    15. public void log(String msg){
    16. System.out.println("[info]使用了" + msg);
    17. }
    18. }
  1. 客户访问代理:
    1. public class User {
    2. public static void main(String[] args) {
    3. //真实对象
    4. UserServiceImpl userService = new UserServiceImpl();
    5. //代理对象
    6. UserServiceProxy userServiceProxy = new UserServiceProxy();
    7. userServiceProxy.setUserService(userService);//代理真实对象
    8. //访问代理方法
    9. userServiceProxy.add();
    10. }
    11. }

9.3、动态代理

  • 动态代理角色和静态代理角色一样

  • 动态代理类是动态生成的,不是我们直接写好的

  • 动态代理分为两大类

    1. 基于接口 JDK 动态代理

    2. 基于类 cglib

    3. java字节码 javassist

需要了解两个类:Proxy 代理、InvocationHandler 调用处理程序

10、AOP

10.1、简介

AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

10.2、Spring实现AOP

【重点】 使用AOP织入需要导入依赖包!

  1. <dependency>
  2. <groupId>org.aspectj</groupId>
  3. <artifactId>aspectjweaver</artifactId>
  4. <version>1.8.13</version>
  5. </dependency>

方式一:使用Spring的API接口【主要SpringAPI接口实现】

方式二:自定义来实现AOP【主要是切面定义】

方式三:使用注解实现

11、整合Mybatis

步骤:

  1. 导入相关jar包

    1. Junit
    2. mybatis
    3. mysql
    4. spring
    5. aop织入
    6. mybatis-Spring
  2. 编写配置文件

    1. <dependencies>
    2. <dependency>
    3. <groupId>junit</groupId>
    4. <artifactId>junit</artifactId>
    5. <version>4.13</version>
    6. <scope>test</scope>
    7. </dependency>
    8. <dependency>
    9. <groupId>mysql</groupId>
    10. <artifactId>mysql-connector-java</artifactId>
    11. <version>5.1.47</version>
    12. </dependency>
    13. <dependency>
    14. <groupId>org.springframework</groupId>
    15. <artifactId>spring-webmvc</artifactId>
    16. <version>5.0.4.RELEASE</version>
    17. </dependency>
    18. <dependency>
    19. <groupId>org.springframework</groupId>
    20. <artifactId>spring-jdbc</artifactId>
    21. <version>5.0.3.RELEASE</version>
    22. </dependency>
    23. <dependency>
    24. <groupId>org.aspectj</groupId>
    25. <artifactId>aspectjweaver</artifactId>
    26. <version>1.8.13</version>
    27. </dependency>
    28. <dependency>
    29. <groupId>org.mybatis</groupId>
    30. <artifactId>mybatis-spring</artifactId>
    31. <version>1.3.1</version>
    32. </dependency>
    33. </dependencies>
  1. 测试

12、声明式事务

1、回顾事务

  • 把一组业务当成一个业务来做:要么都成功,要么都失败
  • 事务在项目开发中,十分的重要,涉及到数据的一致性问题,不能马虎!
  • 确保完整性和一致性

事务的ACID原则

  • 原子性
  • 一致性
  • 隔离性

    • 多个业务可能操作同一个资源,防止资源损坏
  • 持久性

    • 事务一旦提交,无论发生什么问题,都不会影响,被持久化的写到数据库中

2、Spring中的事务管理

  1. 声明式事务【交由容器管理】

    1. 配置声明式事务
      1. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      2. <constructor-arg ref="dataSource" />
      3. </bean>
  1. 结合AOP实现事务的织入
    配置事务通知
    1. <tx:advice id = "" transaction-manage = "">


给哪些方法配置事务

  1. <tx:attribute>
  2. <tx:method name = "add" propagation = ""/>
  3. <tx:method name = ""/>
  4. </tx:attribute>


配置事务切入

  1. 编程式事务

思考:

为什么需要事务