Spring系列

Spring

1、Spring

1.1 简介

  • Spring:春天—->给软件行业带来了春天!
  • 2002,首次推出了Spring框架的雏形:interface21框架!
  • Spring框架即以interface21框架为基础,经过重新设计,并不断丰富内涵,于2004年3月24日,发布了1.0正式版。
  • Rod Johnson,Spring Framework创始人,著名作者。很难想象其学历,真的让好多人大吃一惊,他是悉尼大学的博士,然而他的专业不是计算机,而是音乐学。
  • spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架。
  • SSH:Struct2+Spring+Hibernate!
  • SSM:SpringMVC+Spring+Mybatis!

官网:https://spring.io/projects/spring-framework#overview

官方下载地址:https://repo.spring.io/release/org/springframework/spring/

Github:https://github.com/spring-projects/spring-framework

Maven仓库:导入webmvc包会自动导入相关依赖;jdbc用于和Mybatis整合。

1
2
3
4
5
6
7
8
9
10
11
12
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>

1.2 优点

  • Spring是一个开源的免费的框架(容器)!

  • Spring是一个轻量级的、非入侵式的框架!

  • 控制反转(IOC)、面向切面编程(AOP)!

  • 支持事务的处理,对框架整合的支持!

    总结一句话:Spring就是一个轻量级的控制反转(IOC)和面向切面编程的框架!

1.3 组成

image-20200102001447503

1.4 拓展

在Spring的官网有这个介绍:现代化的java开发!说白了就是基于Spring的开发!

image-20200102001823229

  • Spring Boot
    • 一个快速开发的脚手架。
    • 基于Spring Boot可以快速的开发单个微服务。
    • 约定大于配置!
  • Spring Cloud
    • SpringCloud是基于SpringBoot实现的。

因为现在大多数公司都在使用SpringBoot进行快速开发,学习SpringBoot的前提,需要完全掌握Spring以及SpringMVC!承上启下的作用。

弊端:发展了太久之后,违背了原来的理念!配置十分繁琐,人称:“配置地狱”。

2、 IOC理论推导

1.UserDao接口

2.UserDaoImpl实现类

3.UserService业务接口

4.UserServiceImpl业务实现类

在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改源代码!如果程序代码量十分大,修改一次的成本代价十分昂贵!

我们使用一个Set接口实现,已经发生了革命性的变化!

1
2
3
4
5
6
private UserDao userDao;

//利用set进行动态实现值的注入!
public void setUserDao(UserDao userDao){
this.userDao = userDao;
}
  • 之前,程序是主动创建对象!控制权在程序员手上!
  • 使用了set注入后,程序不再具有主动性,而是变成了被动的接收对象!

这种思想,从本质上解决了问题,我们程序员不用再去管理对象的创建了。系统的耦合性大大降低,可以更加专注在业务的实现上。这是IOC的原型!

image-20200102111735712

image-20200102111753076

IOC本质

控制反转IOC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IOC的一种方法,也有人认为DI是IoC的另一种说法。没有IoC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。

采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方式是依赖注入(Dependency Injection,DI)

3、 Hello Spring

beans.xml官网配置文件:

1
2
3
4
5
6
7
<?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">

</beans>

bean对象添加:

1
2
3
4
5
6
7
8
9
10
<bean id="mysqlImpl" class="com.kuang.dao.UserDaoMysqlImpl"></bean>
<bean id="oracleImpl" class="com.kuang.dao.UserDaoOracleImpl"></bean>

<bean id="UserServiceImpl" class="com.kuang.service.UserServiceImpl">
<!--
ref:引用Spring容器中已经创建好的对象
value:具体的值,基本数据类型
-->
<property name="userDao" ref="mysqlImpl"></property>
</bean>

Test方法:

1
2
3
4
5
//解析beans.xml文件,生成管理相应的Bean对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//getBean:参数即为spring配置文件中bean的id
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello.toString());

思考问题

  • Hello对象是谁创建的?

    hello对象是由Spring创建的。

  • Hello对象的属性是怎么设置的?

    hello对象的属性是由Spring容器设置的。

这个过程就叫做控制反转:

控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring后,对象是由Spring来创建的。

反转:程序本身不创建对象,而变成被动的接收对象。

依赖注入:就是利用set方法来进行注入。

IoC是一种编程思想,由主动的编程编程被动的接收。

可以通过new ClassPathXmlApplicationContext去浏览一下底层源码。

OK,到了现在,我们彻底不用在程序中去改动了,要实现不同的操作,只需要在xml配置文件中进行修改,所谓的IoC,一句话搞定:对象由Spring来创建,管理,装配!

IDEA快捷创建beans.xml文件,自动导入spring配置信息:

image-20200102152125077

4、 IoC创建对象的方式

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

  2. 假设我们要使用有参构造创建对象。

    1.下标赋值。

    1
    2
    3
    4
    <!--第一种,下标赋值!-->
    <bean id="user" class="com.kuang.pojo.User">
    <constructor-arg index="0" value="憨批" />
    </bean>

    2.类型赋值。

    1
    2
    3
    4
    <!--第二种,通过类型创建,不建议使用,重复类型难以分辨-->
    <bean id="user" class="com.kuang.pojo.User">
    <constructor-arg type="java.lang.String" value="大憨批" />
    </bean>

    3.参数名赋值。

    1
    2
    3
    4
    <!--第三种,直接通过参数名来设置-->
    <bean id="user" class="com.kuang.pojo.User">
    <constructor-arg name="name" value="臭憨批" />
    </bean>

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

5、 Spring配置

5.1 别名

1
2
<!--别名,如果添加了别名,我们也可以使用别名获取到-->
<alias name="user" alias="userNew"></alias>

5.2 Bean的配置

1
2
3
4
5
6
7
<!--
id:bean的唯一标识符,相当于我们学的对象名;
class:bean对象所对应的全限定名:包名+类名;
name:也是别名,可以同时取多个别名,逗号分割
-->
<bean id="userT" class="com.kuang.pojo.UserT" name="user2,u2">
</bean>

5.3 import

这个import,一般用于团队开发使用,他可以将多个配置文件,导入合并为一个。

假设,现在项目中有多个人开发,这三个人负责不同的类开发,不同的类需要注册在不同的bean中,我们可以利用import将所有人的beans.xml合并为一个总的!

  • 张三
  • 李四
  • 王五
  • applicationContext.xml
1
2
3
<import resource="beans.xml"/>
<import resource="beans2.xml"/>
<import resource="beans3.xml"/>

使用的时候,直接使用总的配置就可以了。

6、 依赖注入

6.1 构造器注入

之前已经介绍过。

6.2 Set方式注入【重点】

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

【环境搭建】

  1. 复杂类型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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
    10
    public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbies;
    private Map<String,String> card;
    private Set<String> games;
    private String wife;
    private Properties info;
    }
    1. beans.xml

      1
      2
      3
      4
      5
      6
      7
      8
      9
      <?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
      <bean id="student" class="com.kuang.pojo.Student">
      <!--第一种,普通值注入-->
      <property name="name" value="憨批"/>
      </bean>
      </beans>
    2. 测试类

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

    完善注入:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    <?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="address" class="com.kuang.pojo.Address"/>

    <bean id="student" class="com.kuang.pojo.Student">
    <!--第一种,普通值注入,value-->
    <property name="name" value="憨批"/>
    <!--第二种,Bean注入,ref-->
    <property name="address" ref="address"/>
    <!--数组注入-->
    <property name="books">
    <array>
    <value>红楼梦</value>
    <value>西游记</value>
    <value>水浒传</value>
    <value>三国演义</value>
    </array>
    </property>
    <!--List注入-->
    <property name="hobbies">
    <list>
    <value>听歌</value>
    <value>敲代码</value>
    <value>看电影</value>
    </list>
    </property>
    <!--Map-->
    <property name="card">
    <map>
    <entry key="身份证" value="1555555555"/>
    <entry key="银行卡" value="5555555555"/>
    </map>
    </property>
    <!--Set-->
    <property name="games">
    <set>
    <value>lol</value>
    <value>wow</value>
    </set>
    </property>
    <!--null-->
    <property name="wife">
    <null/>
    </property>
    <!--Properties-->
    <property name="info">
    <props>
    <prop key="driver">com.mysql.jdbc.Driver</prop>
    <prop key="url">jdbc:mysql://localhost:3306/news</prop>
    <prop key="root">root</prop>
    <prop key="password">123456</prop>
    </props>
    </property>

    </bean>

    </beans>

6.3 拓展方式注入

我们可以使用c和p命令空间进行注入:

使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<!--p命名空间注入,可以直接注入属性的值:property-->
<bean id="user" class="com.kuang.pojo.User" p:name="憨批" p:age="18"/>

<!--c命名空间注入,通过构造器注入:construct-args-->
<bean id="user2" class="com.kuang.pojo.User" c:age="18" c:name="憨批"/>

</beans>

测试:

1
2
3
4
5
6
@Test
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("userBeans.xml");
User user = context.getBean("user2", User.class);
System.out.println(user);
}

注意点:p和c命名空间不能直接使用,需要导入xml约束!

1
2
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"

6.4 bean的作用域

  1. 代理模式(Spring默认机制):get到的都是同一个对象!

    1
    <bean id="user2" class="com.kuang.pojo.User" c:age="18" c:name="憨批" scope="singleton"/>
  2. 原型模式:每次从容器中get的时候,都会产生一个新的对象!

    1
    <bean id="user2" class="com.kuang.pojo.User" c:age="18" c:name="憨批" scope="prototype"/>
  3. 其余的request、session、application、这些个只能在web开发中使用。

7、 Bean的自动装配

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

在Spring中有三种装配的方式:

  1. 在xml中显式配置;
  2. 在java中显式配置;
  3. 隐式的自动装配bean

7.1 测试

环境搭建:一个人有两个宠物!

7.2 ByName自动装配

1
2
3
4
5
6
<!--
byName:会自动在容器上下文中查找和自己对象set方法后面的值对应的beanid!
-->
<bean id="people" class="com.kuang.pojo.People" autowire="byName">
<property name="name" value="憨批"/>
</bean>

7.3 ByType自动装配

1
2
3
4
5
6
<!--
byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean!必须保证类型全局唯一。
-->
<bean id="people" class="com.kuang.pojo.People" autowire="byType">
<property name="name" value="憨批"/>
</bean>

小结:

  • byName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致!
  • byType的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致!

7.4 使用注解实现自动装配

jdk1.5支持注解,Spring2.5开始支持注解。

要使用注解须知:

  1. 导入约束:context约束。

  2. 配置注解的支持:context:annot-config/

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <?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

直接在属性上使用即可!也可以在set方式上使用!

使用Autowired我们可以不用编写Set方法了,前提是你这个自动装配的属性在IoC(Spring)容器中存在,且符合名字byName!

科普:

1
2
3
4
@Nullable	字段标记了这个注解,说明这个字段可以为null
public People(@Nullable String name){
this.name = name;
}
1
2
3
public @interface Autowired {
boolean required() default true;
}

测试代码:

1
2
3
4
5
6
7
8
public class People {
//如果显式定义了Autowired的required属性为false,说明这个对象可以为null,否则不允许为空
@Autowired(required = false)
private Dog dog;
@Autowired
private Cat cat;
private String name;
}

如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解@Autowired完成的时候,我们可以使用@Qualifier(value=”xxx”)去配置@Autowired的使用,指定一个唯一的bean对象注入!

1
2
3
4
5
6
7
8
9
public class People {
@Autowired
@Qualifier(value="dog11")
private Dog dog;
@Autowired
@Qualifier(value="cat11")
private Cat cat;
private String name;
}

@Resource注解

1
2
3
4
public class People {
@Resource(name = "cat2")
private Cat cat;
}

小结:

@Resource和@Autowired的区别:

  • 都是用来自动装配的,都可以放在属性字段上;

  • @Autowired通过byType的方式实现,而且必须要求这个对象存在!【常用】

  • @Resource默认通过byName的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错!

  • 执行顺序不同:@Autowired通过byType的方式实现,@Resource默认通过byName的方式实现。

8、 使用注解开发

在spring4之后,要使用注解开发,必须要保证aop的包导入了。

image-20200103105725321

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

1
2
<!--指定要扫描的包,这个包下的注解会生效-->
<context:component-scan base-package="com.kuang.pojo"/>
  1. bean

  2. 属性如何注入

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //等价于<bean id="user" class="com.kuang.pojo.User"/>
    //@Component 组件
    @Component
    public class User {
    //相当于<property name="name" value="小憨批"/>
    public String name;
    @Value("小憨批")
    public void setName(String name){
    this.name = name;
    }
    }
  3. 衍生的注解

    @Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层!

    • dao【@Repository】
    • service【@Service】
    • controller【@Controller】

    这四个注解功能都是一样的,都是代表将某个类注册到Spring中,装配Bean!

  4. 自动装配

    1
    2
    3
    4
    -@Autowired:自动装配通过类型,名字
    如果Autowired不能唯一自动装配上属性,则需要通过@Qualifier(value="xxx")
    -@Nullable:字段标记了这个注解,说明这个字段可以为null
    -@Resource:自动装配通过名字,类型
  5. 作用域

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Scope("singleton")
    public class User {
    //相当于<property name="name" value="小憨批"/>
    public String name;
    @Value("小憨批")
    public void setName(String name){
    this.name = name;
    }
    }
  6. 小结

    xml与注解:

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

    xml与注解最佳实践:

    • xml用来管理bean;
    • 注解只负责完成属性的注入;
    • 我们在使用的过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的支持。
    1
    2
    3
     <!--指定要扫描的包,这个包下的注解会生效-->
    <context:component-scan base-package="com.kuang"/>
    <context:annotation-config/>

9、 使用java的方式配置Spring

我们现在要完全不适用Spring的xml配置了,全权交给java来做!

javaConfig是Spring的一个子项目,在Spring4之后,它成为了一个核心功能。

实体类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Component
public class User {
private String name;

public String getName() {
return name;
}

@Value("小笨蛋")
public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import com.kuang.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

//这个也会被Spring容器托管,注册到容器中,因为本来就是一个@Component
//@Configuration代表这是一个配置类,就和我们之前看的beans.xml
@Configuration
@ComponentScan("com.kuang.pojo")
@Import(KuangConfig2.class )
public class KuangConfig {
//注册一个bean,就相当于我们之前写的一个bean标签
//这个方法的名字,就相当于bean标签中的id属性
//这个方法的返回值,就相当于bean标签中的class属性
@Bean
public User getUser(){
return new User();//就是返回要注入到bean的对象
}
}

测试类:

1
2
3
4
5
6
7
8
public class MyTest {
public static void main(String[] args) {
//如果完全使用了配置类方式去做,我们就只能通过AnnotationConfig上下文来获取容器,通过配置类的class对象加载!
ApplicationContext context = new AnnotationConfigApplicationContext(KuangConfig.class);
User getUser = (User) context.getBean("getUser");
System.out.println(getUser.getName());
}
}

这种纯java的配置方式,在SpringBoot中随处可见!

10、 代理模式

为什么要学习代理模式?因为这就是SpringAOP的底层!【SpringAOP 和 SpringMVC 面试必问】

代理模式的分类:

  • 静态代理
  • 动态代理

image-20200104125508118

10.1 静态代理

角色分析:

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

代码步骤:

  1. 接口

    1
    2
    3
    4
    //租房
    public interface Rent {
    public void rent();
    }
  2. 真实角色

    1
    2
    3
    4
    5
    6
    //房东
    public class Host implements Rent {
    public void rent(){
    System.out.println("房东要出租房子!");
    }
    }
  3. 代理角色

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    public class Proxy implements Rent {
    private Host host;

    public Proxy() {
    }
    public Proxy(Host host) {
    this.host = host;
    }

    public void rent(){
    seeHouse();
    host.rent();
    hetong();
    fee();
    }
    //看房
    public void seeHouse(){
    System.out.println("中介带你看房");
    }
    //签合同
    public void hetong(){
    System.out.println("签合同");
    }
    //收费
    public void fee(){
    System.out.println("收取中介费用");
    }
    }
  4. 客户端访问

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class Client {
    public static void main(String[] args) {
    //房东要租房子
    Host host = new Host();
    //代理,中介帮房东租房子,但是呢?代理角色一般会有一些附属操作!
    Proxy proxy = new Proxy(host);
    proxy.rent();
    }
    }

代理模式的好处:

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

缺点:

  • 一个真实角色就会产生一个代理角色,代码量会翻倍,开发效率会变低

10.2 加深理解

代码:对应08-demo02

聊聊AOP

image-20200105210505898

10.3 动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的。
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
    • 基于接口——JDK动态代理
    • 基于类:cglib
    • java字节码实现:javasisit

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

动态代理的好处:

  • 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
  • 公共也就交给代理角色!实现了业务的分工!
  • 公共业务发生扩展的时候,方便集中管理!
  • 一个动态代理类代理类代理的是一个接口,一般就是对应的一类业务
  • 一个动态代理类可以代理多个类,只要是实现了同一个接口即可!

11、 AOP

11.1 什么是AOP

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

image-20200106085441897

11.2 AOP在Spring中的作用

==提供声明式事务;允许用户自定义切面==

  • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点,如日志、安全、缓存、事务等等……
  • 切面(ASPECT):横切关注点被模块化的特殊对象,即是一个类。
  • 通知(Advice):切面必须要完成的工作,即是类中的一个方法。
  • 目标(Target):被通知对象。
  • 代理(Proxy):向目标对象应用通知之后创建的对象。
  • 切入点(PointCut):切面通知执行的“地点”的定义。
  • 连接点(jointPoint):与切入点匹配的执行点。

image-20200106090325307

SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:

image-20200106090428369

即AOP在不改变原有代码的情况下,去增加新的功能。

11.3 使用Spring实现AOP

【重点】使用AOP织入,需要导入一个依赖包。

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>

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

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

方式三:使用注解实现

12、 整合Mybatis

步骤:

  1. 导入相关jar包
    • junit
    • Mybatis
    • mysql数据库
    • spring相关的
    • aop织入
    • mybatis-spring【new知识点】
  2. 编写配置文件
  3. 测试

12.1 回忆mybatis

  1. 编写实体类
  2. 编写核心配置文件
  3. 编写接口
  4. 编写Mapper.xml
  5. 测试

12.2 Mybatis-Spring

  1. 编写数据源配置
  2. sqlSessionFactory
  3. sqlSessionTemplate
  4. 需要给接口加实现类
  5. 将自己写的实现类,注入到Spring中
  6. 测试

13、 声明式事务

13.1 回顾事务

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

事务ADID原则:

  • 原子性
  • 一致性
  • 隔离性
    • 多个业务可能操作同一个资源,防止数据损坏
  • 持久性
    • 事务一旦提交,无论系统发生什么问题,结果都不会再被影响,被持久化的写到存储器中。

13.2 Spring中的事务管理

  • 声明式事务:AOP
  • 编程式事务:需要在代码中,进行事务的管理

思考:

为什么需要事务?

  • 如果不配置事务,可能存在数据提交不一致的情况
  • 如果我们不在Spring中去配置声明式事务,我们就需要在代码中手动配置事务
  • 事务在项目的开发中十分重要,涉及到数据的一致性和完整性问题,不容马虎

总结

参考自javaGuide

什么是Spring框架

我们一般说 Spring 框架指的都是 Spring Framework,它是很多模块的集合,使用这些模块可以很方便地协助我们进行开发。这些模块是:核心容器、数据访问/集成,、Web、AOP(面向切面编程)、工具、消息和测试模块。比如:Core Container 中的 Core 组件是Spring 所有组件的核心,Beans 组件和 Context 组件是实现IOC和依赖注入的基础,AOP组件用来实现面向切面编程。

列举一些重要的Spring模块

  • core:基础,主要提供IOC依赖注入功能。
  • AOP:面向切面编程的实现
  • JDBC :java数据库连接
  • JMS:消息服务
  • WEB:创建web应用程序提供支持
  • Test:提供了对JUnit和TestNG测试的支持。

@RestController和@Controller

restcontroller在spring4之后才有,之前必须使用controller+responsebody

IOC和AOP

  • 对IOC和AOP的理解

    IOC容器实际上就是一个Map(key,value),存放的是各种对象。spring时代通过xml配置bean,在boot时代通过注解配置bean。

    AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码降低模块间的耦合度,并有利于未来的可拓展性和可维护性。基于动态代理的。如果代理的对象,实现了某个接口,使用JDK,没有实现的使用CGLAB代理。

Spring Bean

  • 作用域

    • singleton:唯一bean实例,默认是单例。
    • protype:每次请求都会创建一个新的bean实例
    • request:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。
    • session :每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效。
    • global-session: 全局session作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了。
  • 单例bean的线程安全

    一般情况下,我们常用的 ControllerServiceDao 这些 Bean 是无状态的。无状态的 Bean 不能保存数据,因此是线程安全的。

    常见的两种解决办法:

    • 在类中定义threadLocal成员变量。
    • 改变 Bean 的作用域为 “prototype”:每次请求都会创建一个新的 bean 实例,自然不会存在线程安全问题。
  • @Compnen和@Bean的区别

  • 将一个类声明为Sprng的bean的注解

    一般使用@Autowired注解自动装配bean,想把类标识成可用于autowired自动装配的类,可以使用以下注解:

    • @Component :通用的注解,可标注任意类为 Spring 组件。如果一个Bean不知道属于哪个层,可以使用@Component 注解标注。
    • @Repository : 对应持久层即 Dao 层,主要用于数据库相关操作。
    • @Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao层。
    • @Controller : 对应 Spring MVC 控制层,主要用于接受用户请求并调用 Service 层返回数据给前端页面。
  • bean的生命周期

    Spring Bean 生命周期

SpringMVC

  • 对MVC的理解

    是一种设计模式。

    img

    • Model1时代JSP
    • Model2时代Bean(model)+JSP(View)+Servlet(controller)
  • MVC的工作原理

    1. 客户端(浏览器)发送请求,直接请求到 DispatcherServlet
    2. DispatcherServlet 根据请求信息调用 HandlerMapping,解析请求对应的 Handler
    3. 解析到对应的 Handler(也就是我们平常说的 Controller 控制器)后,开始由 HandlerAdapter 适配器处理。
    4. HandlerAdapter 会根据 Handler 来调用真正的处理器开处理请求,并处理相应的业务逻辑。
    5. 处理器处理完业务后,会返回一个 ModelAndView 对象,Model 是返回的数据对象,View 是个逻辑上的 View
    6. ViewResolver 会根据逻辑 View 查找实际的 View
    7. DispaterServlet 把返回的 Model 传给 View(视图渲染)。
    8. View 返回给请求者(浏览器)

Spring框架中用到的设计模式

  • 工厂模式:创建Bean
  • 代理模式:AOP
  • 单例模式:Bean单例模式
  • 包装器设计模式:Spring 中 jdbcTemplatehibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。
  • 观察者模式:事件驱动

Spring管理事务

  • 管理事务的方式

    • 编程式,不推荐。

    • 声明式事务

      • 基于XML
      • 基于注解
  • 事务的隔离级别

  • 哪几种事务传播行为五种

  • Transactional(rollback=Exception.class)

    @Transactional注解中如果不配置rollbackFor属性,那么事务只会在遇到RuntimeException的时候才会回滚,加上rollbackFor=Exception.class,可以让事务在遇到非运行时异常时也回滚。

使用JPA在数据库中非持久化一个字段。

@Transient

SpringBoot

面试题总结,摘自CSDN

面试题总结

  • 什么是SpringBoot

  • SpringBoot的优点(Spring的缺点)

    1. 容易上手,提升开发效率,为 Spring 开发提供一个更快、更广泛的入门体验。
    2. 开箱即用,远离繁琐的配置。
    3. 提供了一系列大型项目通用的非业务性功能,例如:内嵌服务器、安全管理、运行数据监控、运行状况检查和外部化配置等。
    4. 没有代码生成,也不需要XML配置。
    5. 避免大量的 Maven 导入和各种版本冲突。
  • 核心注解是哪个,由哪几个注解组成

  • SpringBoot Starters

    • starter是什么
    • Spring-Boot-Starters-parent有什么用
      1. 定义了 Java 编译版本为 1.8 。
      2. 使用 UTF-8 格式编码。
      3. 继承自 spring-boot-dependencies,这个里边定义了依赖的版本,也正是因为继承了这个依赖,所以我们在写依赖时才不需要写版本号。
      4. 执行打包操作的配置。
      5. 自动化的资源过滤。
      6. 自动化的插件配置。
      7. 针对 application.properties 和 application.yml 的资源过滤,包括通过 profile 定义的不同环境的配置文件,例如 application-dev.properties 和 application-dev.yml。
  • 支持哪些内嵌servlet容器:Tomcat/Jetty/undertow

  • 如何实现自动装配

    • @EnableAutoConfiguration, @Configuration, @ConditionalOnClass
    • @EnableAutoConfiguration 给容器导入META-INF/spring.factories 里定义的自动配置类。
    • 每一个自动配置类结合对应的 xxxProperties.java 读取配置文件进行自动配置功能
  • 常用注解

    • RestController
    • GetMapping RequestParam
    • PostMapping RequestBodt
    • pathvariable,获取URL中的数据
    • Bean注解
  • 配置文件

    • 两种配置文件YAML properties

    • 什么是YAML

      YAML 是一种人类可读的数据序列化语言。它通常用于配置文件。与属性文件相比,如果我们想要在配置文件中添加复杂的属性,YAML 文件就更加结构化,而且更少混淆。可以看出 YAML 具有分层配置数据。

    • YAML的优势

      1. 配置有序,在一些特殊的场景下,配置有序很关键
      2. 支持数组,数组中的元素可以是基本数据类型也可以是对象
      3. 简洁
    • 能否使用XML配置文件

      @ImportResource 注解可以引入一个 XML 配置。不推荐

    • 读取配置文件的方法

      • 获取环境变量

        1
        2
        ConfigurableApplicationContext ctx = SpringApplication.run(SpringbootPropertiesApplication.class, args);
        ctx.getEnvironment().getProperty("string.port")
      • 通过注解

        @Value(“${string.port}”) private int intPort;

    • 配置文件优先级

      spring.config.location > spring.profiles.active > spring.config.additional-location > 默认的 application.proerties

  • 安全问题

    spring-boot-starter-security 依赖项,并且必须添加安全配置。它只需要很少的代码。配置类将必须扩展WebSecurityConfigurerAdapter 并覆盖其方法。

  • 跨域问题

    跨域

SpringCloud

使用框架开发,一定是越来越简单的。在整合Spring的时候的地狱配置让人头大,于是Boot出现了,而cloud不一样,cloud不是为了改进什么而出现的,它更多是为了适应微服务这一话题而提供的一整套解决方案。既然cloud是一整套的微服务解决方案,那就有必要先来聊聊微服务。

微服务

这词已经不新鲜了,是一种架构风格,将应用程序构建为以业务业务领域为模型的小型自治服务集合。敏捷团队可以使用可用的框架和所选的技术栈构建单独的服务组件。每个服务组件形成一个强大的微服务架构,从而提供更好的拓展性。可以单独处理每个服务组件的问题,从而对整个应用程序没有影响或者影响最小。

微服务的特点和优点

  • 特点
    • 解耦
    • 组件化
    • 自治:开发人员和团队可以彼此独立工作,从而提高速度。
    • 持续交付:CICD
    • 敏捷
  • 优点
    • 独立开发:微服务可以根据各自的功能轻松开发
    • 独立部署
    • 故障隔离:一项不起作用,系统可以继续运行
    • 混合技术栈:可以使用不同的语言开发。来构建同一个应用的不同服务。

cloud

  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

请我喝杯咖啡吧~

支付宝
微信