狂神Spring学习笔记

在这里插入图片描述

一:Spring

  • Spring: 春天 -> 给软件行业带来了春天
  • 2002,首次推出了Spring框架的雏形: interface21
  • 2004年3月24,发布了1.0正式版
  • Rod Johnson -> Spring framework创始人
  • 理念:使现有的技术更加容易使用, 本身是一个大杂烩,整合了现有的技术框架
  • Spring是一个开源的免费的框架(容器),是一个轻量级的、非入侵式的框架
  • 控制反转(IOC),面向切面编程(AOP)
  • 支持事务的处理,对框架整合的支持

Spring就是一个轻量级的控制反转(IOC)和面向切面免除(AOP)的框架

SSH: Struct2 + Spring + Hibernate
SSM: SpringMvc + Spring + MyBatis

pom.xml 依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>
    </dependencies>

二:IOC

(一)理论推导

1.UserDao 接口
2.UserDaoImpl 实现类
3.UserService 业务接口
4.UserServiceImpl 业务实现类

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

使用一个set接口实现,已经发生了革命性的变化。

    private UserDao userDao;

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

思想的差距不是在短期内能够弥补的

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

程序完全不用动,修改配置xml文件中进行修改,对象由Spring来创建、管理、装配

beans.xml

<?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="mysqlImpl" class="com.kuang.dao.UserDaoMysqlImpl"/>
    <bean id="oracleImpl" class="com.kuang.dao.UserDaoOracleImpl"/>

    <bean id="UserServiceImpl" class="com.kuang.service.UserServiceImpl">
<!--        ref: 是引用spring容器中创建好的对象
            value: 具体的值
            -->
        <property name="userDao" ref="oracleImpl"/>
    </bean>

</beans>

测试

public class MyTest {
    public static void main(String[] args) {
        // 用户实际调用的是业务层, dao层不需要接触
//        UserServiceImpl userService = new UserServiceImpl();
//        userService.setUserDao(new UserDaoMysqlImpl());
//        userService.getUser();

        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        UserServiceImpl userServiceImpl = (UserServiceImpl)context.getBean("UserServiceImpl");
        userServiceImpl.getUser();
    }
}

(二)IOC创建对象的方式

1.使用无参构造创建对象,默认
2.假设要使用有参构造创建对象

  • 下标赋值
    <bean id="user" class="com.kuang.pojo.User">
        <constructor-arg index="0" value="夜斗学java"/>
    </bean>
  • 通过类型创建
<!--    通过类型创建-->
    <bean id="user" class="com.kuang.pojo.User">
        <constructor-arg type="java.lang.String" value="夜斗学java"/>
    </bean>
  • 通过参数名
<!--    直接通过参数名来设置-->
    <bean id="user" class="com.kuang.pojo.User">
        <constructor-arg name="name" value="币圈好难受"/>
    </bean>

(三)Bean的配置

        <!--  id: bean的唯一标识符
              class: bean对象所对应的全限定符
              name: 别名-->
        <bean id="userT" class="com.kuang.pojo.UserT"  name="yedou1">
            <constructor-arg name="name" value="币圈好难受" />
        </bean>

        <!--    取别名-->
        <alias name="user" alias="yedou"/>

(四)import

一般用于团队开发,将多个配置文件,导入合并为一个总的配置

<?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">

    <import resource="beans.xml"/>
    <import resource="beans1.xml"/>
</beans>
public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        User user = (User)context.getBean("user");
        user.show();
    }
}

三:依赖注入

  • 构造器注入
  • Set方式注入
  • 拓展方式注入

(一)set方式注入

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

【环境搭建】
1.复杂类型

public class Address {
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

2.真实测试对象

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;
 }

3.beans.xml

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

4.测试类

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

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

        System.out.println(student.getName());
    }
}

完善注入信息

   <bean id="address" class="com.kuang.pojo.Address">
        <property name="address" value="夜斗小神社"/>
    </bean>



    <bean id="student" class="com.kuang.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="hobbys">
            <list>
                <value>写代码</value>
                <value>看电影</value>
                <value>听歌</value>
            </list>
        </property>

        <property name="card">
            <map>
                <entry key="身份证" value="12345"/>
                <entry key="银行卡" value="45678"/>
            </map>
        </property>

        <property name="games">
            <set>
                <value>荒野大表哥</value>
                <value>英雄联盟</value>
                <value>BOB</value>
            </set>
        </property>

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

        <property name="info">
            <props>
                <prop key="学号">190370063</prop>
                <prop key="url">baidu</prop>
                <prop key="username">夜斗</prop>
                <prop key="password">123456</prop>
            </props>
        </property>
    </bean>

(二)p命名和c命名空间

<?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命名空间注入:可以直接注入属性的值-->
    <bean id="user" class="com.kuang.pojo.User" p:name="夜斗"  p:age="21" />

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

四:Bean的自动装配

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

在Spring中有三种自动装配的方式

  • 在xml中显示的配置
  • 在java中显示配置
  • 隐式的自动装配bean

(一):byname与bytype自动装配

    <bean id="cat" class="com.kuang.pojo.Cat"/>
    <bean id="dog" class="com.kuang.pojo.Dog"/>
<!--    byName: 会自动在容器上下文中查找,和自己对象set方法后面的值对应的 beanid
        byType: 会自动在容器上下文中查找, 和自己对象属性类型相同的bean
-->
    <bean id="people" class="com.kuang.pojo.People" autowire="byType">
        <property name="name" value="夜斗"/>
<!--        <property name="dog" ref="dog"/>-->
<!--        <property name="cat" ref="cat"/>-->
    </bean>

(二):注解实现自动装配

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

使用注解:
1.导入约束:context约束
2.配置注解的支持

<?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
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
<!--    开启注解的支持-->
    <context:annotation-config/>

    <bean id="cat" class="com.kuang.pojo.Cat"/>
    <bean id="dog" class="com.kuang.pojo.Dog"/>
    <bean id="people" class="com.kuang.pojo.People">

    </bean>

</beans>

@Autowired
直接在属性上使用即可!也可以在set方式上使用!
使用Autowired我们可以不用编写Set方法,前提是你这个自动装配在IOC容器中存在

@Nullable 字段标记了这个注解,说明这个字段可以为null

public class People {
    // 这个对象可以为空值
    @Autowired(required = false)
    private Cat cat;
    @Autowired
    @Qualifier(value="dog222")
    private Dog dog;
    private String name;
}

五:使用注解开发

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

使用注解要增加context约束,增加注解的支持

1.bean

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

    <!--    开启注解的支持-->
    <context:annotation-config/>
@Component
public class User {
    @Value("yedou")
    public String name;
}

2.属性如何注入

public class User {
    @Value("yedou")
    public String name;
}

3.衍生注解

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

  • dao(@Repository)
  • service(@Service)
  • controller(@Controller)

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

xml与注解:

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

Xml与注解最佳实践

  • xml用于管理bean
  • 注解只负责完成属性的注入
  • 必须让注解生效,就需要开启注解的支持

六:使用Java的方式配置Spring

我们现在完全不使用Spring的Xml的配置了,全程交给java来做

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

实体类

package com.kuang.pojo;


import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
// 这个类被Spring接管了,注册到了容器中
@Component
public class User {

    private String name;

    public String getName() {
        return name;
    }
    @Value("yedou")
    public void setName(String name) {
        this.name = name;
    }

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

配置类

package com.kuang.config;

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;

// 代表这是一个配置类,就和之前beans.xml一样
@Configuration
@ComponentScan("com.kuang.pojo")
@Import(YeConfig2.class)
public class YeConfig {
    // 注册一个Bean,就相当于我们之前写的一个bean标签
    // 这个方法的名字就相当于bean标签中的id属性
    // 这个方法的返回值就相当于bean标签中的class属性
    @Bean
    public User getuser(){
        // 要注入到bean的对象
        return new User();
    }
}

测试类

import com.kuang.config.YeConfig;
import com.kuang.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


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

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

六:代理模式

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

代理模式的分类:

  • 静态代理
  • 动态代理

(一)静态代理

角色分析:

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

1.接口

public interface Rent {
    public void rent();
}

2.真实角色

// 房东
public class Host implements Rent{


    public void rent() {
        System.out.println("房东要出租房子");
    }
}

3.代理角色

public class Proxy implements Rent{
    private Host host;

    public Proxy() {
    }

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



    public void rent() {
        seeHouse();
        host.rent();
        hetong();
        fare();
    }
    // 看房
    public void seeHouse(){
        System.out.println("中介带你看房");
    }

    // 收中介费
    public void fare(){
        System.out.println("收中介费");
    }

    // 签合同
    public void hetong(){
        System.out.println("收中介费");
    }
}

4.客户端访问代理角色

public class Client {
    public static void main(String[] args) {
        Host host = new Host();
        Proxy proxy = new Proxy(host);
        proxy.rent();
    }
}

代理模式的好处:

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

缺点:

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

(二)动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的代理是动态生成的,不是我们直接写好的
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理

基于接口: JDK动态代理
基于类:cglib
java字节码实现:javasist

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

动态代理的好处:

  • 一个动态代理类代理的是一个接口,一般就是一类业务
  • 一个动态代理类可以代理多个类,只要实现了同一个接口即可

七:AOP

<?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:aop="http://www.springframework.org/schema/aop"
       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.xsd">



    <bean id="userService" class="com.kuang.service.UserServiceImpl"/>
    <bean id="log" class="com.kuang.log.Log"/>
    <bean id="afterLog" class="com.kuang.log.AfterLog"/>
<!--&lt;!&ndash;    方式一:使用原生Spring API接口&ndash;&gt;-->
<!--    <aop:config>-->
<!--&lt;!&ndash;        切入点&ndash;&gt;-->
<!--        <aop:pointcut id="pointcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>-->
<!--&lt;!&ndash;        &ndash;&gt;-->
<!--&lt;!&ndash;        执行环绕增强&ndash;&gt;-->
<!--        <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>-->
<!--        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>-->
<!--    </aop:config>-->

<!--    方式二:自定义类-->
    <bean id="diy" class="com.kuang.diy.DiyPointCut"/>

    <aop:config>
<!--        自定义切面,ref 要引用的类-->
        <aop:aspect ref="diy">
<!--            切入点-->
            <aop:pointcut id="point" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<!--            通知-->
            <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>
</beans>

八:整合Mybatis

步骤:
1.导入相关的jar包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.kuang</groupId>
    <artifactId>spring-study</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <modules>
        <module>spring-01-ioc1</module>
        <module>spring-02-hellospring</module>
        <module>spring-03-ioc2</module>
        <module>spring-04-di</module>
        <module>spring-05-Autowired</module>
        <module>spring-06-anno</module>
        <module>spring-07-appconfig</module>
        <module>spring-08-proxy</module>
        <module>spring-09-aop</module>
        <module>spring-10-mybatis</module>
    </modules>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>


    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.23</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.5</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.2</version>
        </dependency>
    </dependencies>
</project>

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

九:声明式事务

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

事务ACID原则:

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

(一):spring中的事务管理

声明式事务;AOP
编程式事务:

<!--    配置声明式事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"/>
    </bean>

<!--    结合AOP实现事物的织入-->
<!--    配置事务的通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--        给哪些方法配置事务-->
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED"/>
<!--            <tx:method name="delete"/>-->
<!--            <tx:method name="update"/>-->
<!--            <tx:method name="query"/>-->
<!--            <tx:method name="*"/>-->
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <aop:pointcut id="txPoint" expression="execution(* com.kuang.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
    </aop:config>

</beans>