Spring5-study

1、spring

1.1、简介

  • Spring:春天—>给软件行业带来了春天!

  • 2002年,首次推出了Spring框架的雏形:interface21框架!

  • Spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日,发布了1.0正式版。

  • Spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架

  • SSH:Struct2 + Spring + Hibernate

  • SSM:SpringMVC + Spring + Mybatis!

官网:https://spring.io/

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

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

spring依赖
<dependency>
   <groupId>org.springframeworkgroupId>
   <artifactId>spring-webmvcartifactId>
   <version>5.2.0.RELEASEversion>
dependency>
spring整合jdbc依赖
<dependency>
   <groupId>org.springframeworkgroupId>
   <artifactId>spring-jdbcartifactId>
   <version>5.2.0.RELEASEversion>
dependency>

1.2、优点

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

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

1.3、组成

Spring5-study_第1张图片

1.4、拓展

在Spring官网有这样一句话:现代化的Java开发,说白了就是基于Spring的开发!

Spring5-study_第2张图片

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

因为现在大多数攻速都在使用SpringBoot进行快速开发,学习SpringBoot的前提,需要完全掌握Spring及SpringMVC!

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

2、IOC理论推导

1.UserDao业务接口

2.UserDaoImpl实现类

3.UserService业务接口

4.UserServiceImpl业务实现类

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

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

private UserDao userDao;

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

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

之前:

Spring5-study_第3张图片

现在:

Spring5-study_第4张图片

2.1、IOC本质

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

Spring5-study_第5张图片

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

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

3、Hello Spring

public static void main(String[] args) {

        //获取Spring的上下文对象!
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        Hello hello = (Hello) context.getBean("hello");

        System.out.println(hello.toString());
    }

思考问题

  • Hello对象是谁创建的?

    Hello对象是由Spring创建的

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

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

这个过程就叫控制反转:

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

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

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

IOC是一种编程思想,由主动的编程变成被动的接收

可以通过newClassPathXmlApplicationContext去浏览一个底层源码

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

4、IOC创建对象的方式

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

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

  • 下标赋值
<!--第一种,下标赋值-->
<bean id="user" class="pojo.User">
     <constructor-arg index="0" value="孤生"/>
</bean>
  • 类型赋值
<!--第二种,通过类型创建,不建议使用-->
<bean id="user" class="pojo.User">
     <constructor-arg type="java.lang.String" value="孤生"/>
</bean>
  • 参数名赋值
<!--直接通过参数名来设置-->
<bean id="user" class="pojo.User">
     <constructor-arg name="name" value="孤生"/>
</bean>

总结:在配置文件加载时,Spring容器中管理的对象就已经被实例化了,不管是否get!

5、Spring配置

5.1、别名


    <alias name="user" alias="u2"/>

5.2、Bean的配置


<bean id="userT" class="pojo.User" name="user2 user3,user4">
    <constructor-arg name="name" value="孤生"/>
bean>

5.3、import

<import resource="bean.xml"/>

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

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

  • 张三
  • 李四
  • 赵武
  • applicationContext.xml

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

6、依赖注入(DI)

6.1、构造器注入

前面已经讲过了

6.2、Set方式注入[重点]

  • 依赖注入:Set注入

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

[搭建环境]

  • 复杂类型
public class Address {
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}
  • 真实测试对象
public class Student {

    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String,String> card;
    private Set<String> games;
    private String wife;
    private Properties info;
  • beans.xml
<bean id="address" class="pojo.Address">
    <property name="address" value="西安"/>
bean>

<bean id="student" class="pojo.Student">
    <property name="name" value="孤生"/>

    <property name="address" ref="address"/>

    <property name="books">
        <array>
            <value>红楼梦value>
            <value>三国演义value>
            <value>水浒传value>
            <value>西游记value>
        array>
    property>

    <property name="card">
        <map>
            <entry key="学生证" value="1234635869574"/>
            <entry key="身份证" value="1564613216546464"/>
        map>
    property>

    <property name="games">
        <set>
            <value>LOLvalue>
            <value>COCvalue>
            <value>BOBvalue>
        set>
    property>

    <property name="hobbys">
        <list>
            <value>value>
            <value>value>
            <value>Rapvalue>
        list>
    property>

    <property name="wife">
        <null/>
    property>

    <property name="info">
        <props>
            <prop key="url">jdbc........prop>
            <prop key="drive">com........prop>
            <prop key="username">rootprop>
            <prop key="password">rootprop>
        props>
    property>

bean>

  • 测试类
public class MyTest {

    public static void main(String[] args) {
       ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        Student student = (Student) context.getBean("student");

        String s = student.toString();

        System.out.println(s);
    }

}

6.3、拓展方式注入

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

官方解释:

<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"
    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="[email protected]"/>
    bean>

    <bean name="p-namespace" class="com.example.ExampleBean"
        p:email="[email protected]"/>
beans>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    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"/>

    
    <bean id="beanOne" class="x.y.ThingOne">
        <constructor-arg name="thingTwo" ref="beanTwo"/>
        <constructor-arg name="thingThree" ref="beanThree"/>
        <constructor-arg name="email" value="[email protected]"/>
    bean>

    
    <bean id="beanOne" class="x.y.ThingOne" c:thingTwo-ref="beanTwo"
        c:thingThree-ref="beanThree" c:email="[email protected]"/>

beans>

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

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

6.4、bean的作用域

Spring5-study_第6张图片

1、单例模式(Spring默认机制)

<bean id="student" class="pojo.Student" scope="singleton">

Spring5-study_第7张图片

2、原型模式:每次从容其中get的时候,都会产生一个新对象!

<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>

Spring5-study_第8张图片

3、其余的request、session、application这些只能在web开发中使用!

7、Bean的自动装配

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

在Spring中有三种装配方式:

  • 在xml中显式的配置
  • 在Java中显式的配置
  • 隐式的自动装配Bean[重要]

7.1、byName自动装配

<bean id="cat" class="pojo.cat"/>
<bean id="dog" class="pojo.dog"/>

<bean id="person" class="pojo.person" autowire="byName">
<property name="name" value="孤生呀"/>
bean>

7.2、byType自动装配

    <bean class="pojo.cat"/>
    <bean class="pojo.dog"/>

    <bean id="person" class="pojo.person" autowire="byType">
        <property name="name" value="孤生呀"/>
    bean>

小结:byName,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法一致!

​ byType,需要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性的类型一致!

7.3、使用注解实现自动装配

jdk1.5支持的注解,Spring2.5就支持了!

要使用注解须知:

  • 导入约束:context约束

  • 配置注解的支持:

    
    <context:annotation-config/>
    

完整配置:

<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!

测试代码

public class person {

    private String name;
    //如果显式的定义了Autowired的required属性为false,说明这个对象可以为null,否则不允许为空
    @Autowired(required = false)
    private cat cat;
    @Autowired
    private dog dog;
}

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

@Resource注解

public class person {

    private String name;
    @Resource(name = "cat22")
    private cat cat;
    @Resource
    private dog dog;
}

8、使用注解开发

  • bean

  • 属性如何注入

    在类型名或者set方法上@Value(“xxx”)

  • 衍生的注解

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

    • dao [@Repository]
    • service [@Service]
    • controller [@Controller]

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

  • 自动装配

    详细见上面

  • 作用域

    @Component

    @Scope(“作用域”)

  • 小结

    xml与注解:

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

    xml与注解最佳实践:

    • xml用来管理bean
    • 注解只负责属性的注入
    • 我们在使用的过程中,必须要注意一个问题:想让注解生效,必须开启注解的支持!

9、使用Java的方式配置Spring

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

JavaConfig是Spring的一个子项目,在Spring 4之后,它成为了核心内容!

实体类

public class User {


    private String name;

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    @Value("孤生")
    public void setName(String name) {
        this.name = name;
    }
}

配置类

@Configuration//这个也会被Spring容器托管,注册到容器中,因为他本来就是个组件
public class JavaConfig {

    @Bean
    public User getUser(){
        return new User();
    }

}

测试类

public class MyTest {

    public static void main(String[] args) {

       ApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);

        User getUser = context.getBean("getUser", User.class);

        System.out.println(getUser.getName());

    }

}

10、代理模式

为什么要学习代理模式?

​ 因为这就是SpringAOP的底层

面试必问 [SpringAOP 和 SpringMVC]

代理模式分类:

  • 静态代理
  • 动态代理

Spring5-study_第9张图片

10.1静态代理

角色分析:

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

代理模式的好处:

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

代理模式的缺点:

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

10.2、静态代理再理解

Demo:

抽象角色类:

public interface UserService {

    public void add();
    public void delete();
    public void update();
    public void query();

}

真实角色类:

//真实对象
public class UserServiceImpl implements UserService {
    public void add() {
        System.out.println("增加了一个用户");
    }

    public void delete() {
        System.out.println("删除了一个用户");
    }

    public void update() {
        System.out.println("更新了一个用户");
    }

    public void query() {
        System.out.println("查询了一个用户");
    }
}

代理对象类:

public class UserServiceProxy implements UserService {

    private UserServiceImpl userService;

    public void setUserService(UserServiceImpl userService) {
        this.userService = userService;
    }

    public void add() {
        log("add");
        userService.add();
    }

    public void delete() {
        log("delete");
        userService.delete();
    }

    public void update() {
        log("update");
        userService.update();
    }

    public void query() {
        log("query");
        userService.query();
    }

    public void log(String msg){
        System.out.println("[Debug] 使用了"+msg+"方法");
    }
}

测试类:

public class Client {

    public static void main(String[] args) {

        UserServiceImpl userService = new UserServiceImpl();

        UserServiceProxy userServiceProxy = new UserServiceProxy();

        userServiceProxy.setUserService(userService);

        userServiceProxy.add();

    }
}

10.3、AOP图解

Spring5-study_第10张图片

10.4、动态代理

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

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

  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理

    • 基于接口:JDK动态代理 [我们用的]
    • 基于类:cglib
    • Java字节码:javasist

需要了解两个类:

  • Proxy:代理
  • InvocationHandler:调用处理程序

动态代理实现:

public class InvocationHandler implements java.lang.reflect.InvocationHandler {

    //被代理的接口
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    //生成得到代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    //处理代理实例,并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        log(method.getName());

        Object invoke = method.invoke(target, args);

        return null;
    }

    public void log(String msg){
        System.out.println("使用了"+msg+"方法");
    }

}

测试程序:

public class Client {

    public static void main(String[] args) {

        //真实对象
        UserServiceImpl userService = new UserServiceImpl();

        //代理角色,不存在
        InvocationHandler pih = new InvocationHandler();

        //设置要代理的对象
        pih.setTarget(userService);

        //动态生成代理类
        UserService proxy = (UserService) pih.getProxy();

        proxy.add();

    }

}

11、AOP

11.1、使用Spring实现Aop

[重点]使用AOP,需要导入一个依赖


<dependency>
    <groupId>org.aspectjgroupId>
    <artifactId>aspectjweaverartifactId>
    <version>1.9.5version>
dependency>

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

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

方式三:使用注解实现!

12、整合Mybatis

步骤:

1、导入相关jar包

  • junit
  • mybatis
  • mysql数据库
  • Spring相关包
  • aop织入
  • mybatis-spring 【new】

2、编写配置文件

3、测试

13、声明式事务

13.1、回顾事务

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

事务ACID原则:

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

你可能感兴趣的:(Spring5-study)