基于狂神的Spring学习

Spring

学习视频链接:https://www.bilibili.com/video/BV1WE411d7Dv

1、简介

1.1、历史与maven配置

  • 2002,首次推出了Spring的雏形:interface 21

  • Rod Johnson, Spring Framework创始人

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

  • SSH:struct2 + Spring + Hibernate

  • SSM:SpringMVC + Spring + Mybatis

    官网文档:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#spring-core

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

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

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.2.4.RELEASE</version>
    </dependency>
    

1.2、优点

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

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

1.3、组成

在这里插入图片描述

1.4、拓展

现代化的Java开发,就是基于Spring的开发

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

大多数公司都基于SpringBoot进行快速开发,学习SpringBoot的前提,需要完全掌握Spring以及SpringMVC。

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

2、OC理论推导

2.1、理论推导

1.UserDao接口

package com.wang.dao;
public interface UserDao {
    void getUser();
}

2.UserDaoImpl

package com.wang.dao;
public class UserDaoImpl implements UserDao {
    public void getUser() {
        System.out.println("默认获取用户的数据");
    }
}
package com.wang.dao;
public class UserDaoMySQLImpl implements UserDao {
    @Override
    public void getUser() {
        System.out.println("MySQL获取数据");
    }
}
package com.wang.dao;
public class UserDaoOracleImpl implements UserDao {
    @Override
    public void getUser() {
        System.out.println("Oracle获取用户数据");
    }
}

3.UserService 业务接口

package com.wang.service;
public interface UserService {
    void getUser();
}

4.UserServiceImpl 业务实现类

package com.wang.service;
import com.wang.dao.UserDao;
import com.wang.dao.UserDaoImpl;
import com.wang.dao.UserDaoMySQLImpl;
import com.wang.dao.UserDaoOracleImpl;

public class UserServiceImpl implements UserService {
    //创建哪一种UserDao的实现类,在代码中写死了,如果需要变更则需要改变源代码
    private UserDao userDao = new UserDaoMySQLImpl();
    public void getUser() {
        userDao.getUser();
    }
}

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

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

public class UserServiceImpl implements UserService {
 		private UserDao userDao;
    //利用set进行动态实现值的注入
    public void setUserDao(UserDao userDao){
        this.userDao = userDao;
    }
    public void getUser() {
        userDao.getUser();
    }
}
  • 之前程序是主动创建对象!控制权在程序员手上,用户的每一个需求都要程序员修改源代码
  • 使用了set注入后,程序不再具有主动性,而是变成了被动接收对象,外部只要传入 一个任意的UserDao的实现类,就可以创建出对应的对象
  • 原来的是程序控制,变成了用户控制
  • 这种思想从本质上解决了问题,程序员不用主动地去管理对象的创建了。系统的耦合性大大降低,可以更加专注在业务的实现上。
  • 这是IoC的原型

2.2、IOC本质

  • 之前的设计思想

    在这里插入图片描述

  • 如今的设计思想

    在这里插入图片描述

  • 控制反转(inversion of control)是一种设计思想,DI(dependency injection)依赖注入是一种实现IoC的方式。

  • 在没有IoC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖完全硬编码在程序中,对象的创建由自己控制,控制反转后将对象的创建转移到了第三方

  • IoC是Spring框架的核心内容,使用多种方式完美实现了IoC,可以使用XML配置,也可以使用注解。新版本的Spring也可以零配置实现IoC

  • Spring容器在初始化时先读取配置文件,根据配置文件或者元数据创建与组织对象存入容器,程序使用时再从IoC容器中取出所需要的对象

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

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

3、HelloSpring

pojo

package com.wang.pojo;

public class Hello {
    private String name;

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

ApplicationContext.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">

    <!--使用Spring创建对象,在Spring中这些都称为Bean-->
    <!--bean = 对象
        Hello hello = new Hello();

        id= 变量名
        class= 要new的对象
        property 相当于给对象中的属性设置一个值
     -->
    <bean id="hello" class="com.wang.pojo.Hello">
        <property name="name" value="String"/>
    </bean>

</beans>

test

import com.wang.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        //获取spring的上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        //我们的对象现在都在spring中管理,我们要使用直接取出来就可以
        Hello hello = (Hello) context.getBean("hello");
        System.out.println(hello.toString());
    }
}

这个过程就要控制反转:

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

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

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

4、IOC对象创建方式

  1. 使用无参构造方法创建对象(默认实现)

  2. 使用有参方法创建对象
    1.下标赋值

    <?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 = "user" class="com.neil.pojo.User">
            <constructor-arg index="0" value="neill"/>
        </bean>
    </beans>
    

    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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id = "user" class="com.neil.pojo.User">
            <constructor-arg type="java.lang.String" value="neill"/>
        </bean>
    </beans>
    

    3.直接通过参数名来命名

    <?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 = "user" class="com.neil.pojo.User">
            <constructor-arg name="name" value="neil"/>
        </bean>
    </beans>
    

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

5、Spring配置

5.1、别名

ApplicationContext.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 = "user" class="com.neil.pojo.User">
        <constructor-arg name="name" value="neil"/>
    </bean>

    <alias name="user" alias="user2"/>
</beans>

test:

import com.wang.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    @Test
    public void Test(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
				//使用别名获取对象
        User user = (User) applicationContext.getBean("user2");
        user.show();
    }
}

5.2、bean配置

<bean id="userN" class="com.neil.pojo.UserN" name="userN2,userN3;userN4 userN5">
  <property name="name" value="Jackson"/>
</bean>
  • id:bean的唯一标识符,也就是我们学的对象名
  • class:bean的全限定名字,包名+类型
  • name:也是别名,也可以同时取多个别名进行分割

5.3、import

一般用于团队开发使用,可以将多个配置文件合并成一个

  1. 在resource目录下创建bean1.xml
  2. ApplicationContext.xml中import
<import resource="bean1.xml"/>

6、依赖注入

6.1、构造器注入

<bean id = "user" class="com.neil.pojo.User">
  <constructor-arg name="name" value="wang"/>
</bean>

6.2、Set方法注入(重点)

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

【环境搭建】

1.复杂类型

package com.wang.pojo;

public class Address {
    private String address;

    public String getAddress() {
        return address;
    }

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

2.真实测试对象

package com.wang.pojo;

import java.util.*;

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 Properties info;
    private String wife;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", address=" + address +
                ", books=" + Arrays.toString(books) +
                ", hobbys=" + hobbys +
                ", card=" + card +
                ", games=" + games +
                ", info=" + info +
                ", wife='" + wife + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

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

    public String[] getBooks() {
        return books;
    }

    public void setBooks(String[] books) {
        this.books = books;
    }

    public List<String> getHobbys() {
        return hobbys;
    }

    public void setHobbys(List<String> hobbys) {
        this.hobbys = hobbys;
    }

    public Map<String, String> getCard() {
        return card;
    }

    public void setCard(Map<String, String> card) {
        this.card = card;
    }

    public Set<String> getGames() {
        return games;
    }

    public void setGames(Set<String> games) {
        this.games = games;
    }

    public Properties getInfo() {
        return info;
    }

    public void setInfo(Properties info) {
        this.info = info;
    }

    public String getWife() {
        return wife;
    }

    public void setWife(String wife) {
        this.wife = wife;
    }
}

3.ApplicationContext.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">

    <!--第一种,普通值注入,value-->
    <bean id="student" class="com.wang.pojo.Student">
        <property name="name" value=""/>
    </bean>
</beans>

5.测试类

import com.wang.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        Student student = (Student) context.getBean("student");
        System.out.println(student.getName());
    }
}

6.完善注入信息

<?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.wang.pojo.Address">
        <property name="address" value="山东"/>
    </bean>
    <bean id="student" class="com.wang.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="hobbys">
            <list>
                <value>LOL</value>
                <value>CSGO</value>
                <value>敲代码</value>
            </list>
        </property>
        <!--第五种,map注入-->
        <property name="card">
            <map>
                <entry key="身份证" value="1312313123123313"/>
                <entry key="银行卡" value="123213213213123321312312"/>
            </map>
        </property>
        <!--第六种,set注入-->
        <property name="games">
            <set>
            <value>LOL</value>
            <value>CSGO</value>
            </set>
        </property>
        <!--第七种,null注入-->
        <property name="wife">
            <null/>
        </property>
        <!--第八种,Properties注入-->
        <property name="info">
            <props>
                <prop key="学号">20190525</prop>
                <prop key="性别"></prop>
                <prop key="姓名">小明</prop>
            </props>
        </property>
    </bean>
</beans>

7.打印结果

Student{name='王', address=Address{address='山东'}, books=[红楼梦, 水浒传, 三国演戏, 西游记], hobbys=[LOL, CSGO, 敲代码], card={身份证=1312313123123313, 银行卡=123213213213123321312312}, games=[LOL, CSGO], info={学号=20190525, 性别=, 姓名=小明}, wife='null'}

6.3、拓展方式注入

我们可以使用p命名和c命名的方式注入,一个利用有参构造,一个利用无参构造

代码如下:

<?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:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--p命名空间注入,可以直接注入属性的值:property-->
    <bean id="user" class="com.wang.pojo.User" p:age="29" p:name="123"/>

    <!--c命名空间注入,可以通过构造器注入:construct-args-->
    <bean id="user2" class="com.wang.pojo.User" c:name="wang" c:age="123"/>
</beans>

注意:在使用时需要加约束

  xmlns:p="http://www.springframework.org/schema/p"//p命名约束
  xmlns:c="http://www.springframework.org/schema/c"//c命名约束

6.4、Bean作用域

ScopeDescription
singleton(Default) Scopes a single bean definition to a single object instance for each Spring IoC container.//单例模式
prototypeScopes a single bean definition to any number of object instances.
requestScopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext.
sessionScopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.
applicationScopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.
websocketScopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext.

重点学习:

1.单例作用域(spring默认机制)

Only one shared instance of a singleton bean is managed, and all requests for beans with an ID or IDs that match that bean definition result in that one specific bean instance being returned by the Spring container.

To put it another way, when you define a bean definition and it is scoped as a singleton, the Spring IoC container creates exactly one instance of the object defined by that bean definition. This single instance is stored in a cache of such singleton beans, and all subsequent requests and references for that named bean return the cached object. The following image shows how the singleton scope works:

在这里插入图片描述

也可以显式增加作用域

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

2.原型模式

The non-singleton prototype scope of bean deployment results in the creation of a new bean instance every time a request for that specific bean is made. That is, the bean is injected into another bean or you request it through a getBean() method call on the container. As a rule, you should use the prototype scope for all stateful beans and the singleton scope for stateless beans.

The following diagram illustrates the Spring prototype scope:

在这里插入图片描述

每次从容器中getBean的时候都会产生一个新的对象

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

3.Request、Session、application

只在web开发中使用

7、Bean的自动装配

7.1、一个人有两个宠物

pojo:

package com.wang.pojo;

public class Cat {
    public void shout(){
        System.out.println("miao");
    }
}
package com.wang.pojo;

public class Dog {
    public void shout(){
        System.out.println("wang");
    }
}

package com.wang.pojo;

public class People {
    private Dog dog;
    private Cat cat;
    private String name;

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    public Cat getCat() {
        return cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "People{" +
                "dog=" + dog +
                ", cat=" + cat +
                ", name='" + name + '\'' +
                '}';
    }
}

ApplicationContext.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="cat" class="com.neil.pojo.Cat"/>
    <bean id="dog" class="com.neil.pojo.Dog"/>

    <bean id="person" class="com.neil.pojo.Person">
        <property name="name"  value="Neil"/>
        <property name="dog" ref="dog"/>
        <property name="cat" ref="cat"/>
    </bean>
</beans>

test:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    @Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        People people = context.getBean("people",People.class);
        people.getCat().shout();
        people.getDog().shout();
    }
}

7.2、ByName自动装配

<?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="cat" class="com.wang.pojo.Cat"/>
    <bean id="dog" class="com.wang.pojo.Dog"/>
    <!--byName:会自动在容器上下文中查找,和自己对象set方法属性对应名称相同的的bean ID-->
    <bean id="people" class="com.wang.pojo.People" autowire="byName">
        <property name="name" value="小驴"/>
        <!--<property name="dog" ref="dog"/>-->
        <!--<property name="cat" ref="cat"/>-->
    </bean>
</beans>

7.3、ByType自动装配

<?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="cat" class="com.wang.pojo.Cat"/>
    <bean id="dog" class="com.wang.pojo.Dog"/>
    <!--byType: 会自动在容器上下文中查找,和自己对象属性类型对应的Bean-->
    <!--需要保证这个类型全局唯一-->
    <bean id="people" class="com.wang.pojo.People" autowire="byType">
        <property name="name" value="小驴"/>
        <!--<property name="dog" ref="dog"/>-->
        <!--<property name="cat" ref="cat"/>-->
    </bean>
</beans>

小结:

  • byName:需要保证所有Bean的Id唯一,会自动在容器上下文中查找,和自己对象set方法属性对应名称相同的的bean ID
  • byType:需要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性的类型一致

7.4、使用注解自动装配

Jdk1.5支持注解,spring2.5就支持注解了

要使用注解须知:

  1. 导入约束:context约束, beans头文件
  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
        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/>
    <!--指定扫描的包,这个包下面的注解就会生效-->
    <context:component-scan base-package="com.wang.pojo"/>
</beans>
  • @Autowired:直接在属性上使用即可!也可以在set方法上使用。使用Autowired我们可以不用编写Set方法,前提是自动装配的属性在IoC(Spring)容器中存在,且装配方式为byType
  • @Resource:默认按照ByName进行实现,找不到就用ByType
  • @Autowired = (required = false):表示忽略当前要注入的bean,如果有直接注入,没有跳过,不会报错。
  • @Qualifier(value="dog"):表示显示注册哪个Bean,如果自动装配环境复杂,需要配合自动装配注解一起使用
  • @Resource:是java的注解,用的比较少,效果等于以上两个的集合,可以使用@Resource(name = 'cat2')指定装配
  • @Nullable:字段标记了这个注解,说明这个字段可以为null

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ssuQGEN4-1599130682121)(E:\狂神笔记和代码\spring5学习.assets\image-20200817175057087.png)]

@Resource@Autowired的区别:

  • 都是用来自动装配的,都可以放在属性字段上
  • @Autowired通过ByType方式实现(常用)
  • @Resource通过ByName方式实现,如果找不到通过ByType实现!如果两个都找不到的情况下就会报错(常用)
  • 执行顺序不同:@Autowired通过ByType方式实现,@Resource通过ByName方式实现,如果找不到通过ByType实现!如果两个都找不到的情况下就会报错

8、使用注解开发

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

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

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

8.1、bean

  • @Componente
//@Component:等价于 `<bean id="user" class="com.wang.pojo.User"/>
package com.wang.pojo;

import org.springframework.stereotype.Component;
//@Component:等价于 <bean id="user" class="com.neil.pojo.User"/>
@Component
public class User {
    public String name = "小驴";
}
  • @value
package com.wang.pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//@Component:等价于 <bean id="user" class="com.neil.pojo.User"/>
@Component
public class User {
    //在属性或者set上注入,与上面等同,也等同于<property name="name" value="小驴"/>
    @Value("小驴")
    public String name ;
}

8.2、属性如何注入

package com.wang.pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//@Component:等价于 <bean id="user" class="com.neil.pojo.User"/>
@Component
public class User {
    //在属性或者set上注入,与上面等同,也等同于<property name="name" value="小驴"/>
    @Value("小驴")
    public String name ;
}

8.3、衍生的注释

@Component有几个衍射注解,我们在web开发中,会按照mvc三层架构分层,功能和@Component类似

  • Dao:使用@Repository注解
  • Service:使用@Service注解
  • controller:使用@Controller注解

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

8.4、自动装配置

  • @Autowired
  • @Resource
  • @Nullable

8.5、作用域

  • @Scope: 可以设置在类上,设置value值,包括Singleton,prototype等

8.6、小结

xml与注解:

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

xml与注解最佳实践:

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

9、使用Java的方式配置Spring

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

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

1.配置Config类

package com.wang.config;

import com.wang.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;

@Configuration //这个也会被spring接管,注册到容器中,因为它本来就是一个@Component,
// @Configuration本来是一个@Conponent组件,代表这是一个配置类,和ApplicationContext.xml一样
@ComponentScan("com.wang.pojo")
@Import(WangConfig2.class)
public class WangConfig {


    /*注册的Bean,相当于我们之前写的Bean
    这个方法的名字,相当于原来Bean标签的Id属性
    这个方法的返回值,相当于bean标签中的class属性*/
    @Bean
    public User getUser(){

        return new User();
    }
}

2.pojo

package com.wang.pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;

//这个注解的意思,就是说这个类被spring接管了,注册到了容器中
@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 + '\'' +
                '}';
    }
}

3.test

import com.wang.config.WangConfig;
import com.wang.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(WangConfig.class);
        User getUser = (User) context.getBean("getUser");
        System.out.println(getUser.getName());
    }
}

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

10、代理模式

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

代理模式原型:

在这里插入图片描述

10.1、静态代理

角色分析:

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

代码实现:

  • 接口

    public interface Rent{
      public void rent();
    }
    
  • 真实角色

    public class Landlord implements Rent(){
      public void rent(){
        System.out.Println("我是房东我有个房子需要出租")
      }
    }
    
  • 代理角色

    public class Proxy implements Rent(){
      private Landlord landlord;
      
      public Proxy(){  
      }
      
      public Proxy(Landlord landlord){
        this.landlord = landlord;
      }
      
      public void rent(){
        inspection();
        landlord.rent();
       	signContract();
        getFee();
      }
      
      public void insepection(){
        System.out.println("中介带你看房子");
      }
      
      public void signContract(){
        System.out.println("和中介签合同了");
      }
      
      public void getFee(){
        System.out.println("收中介费");
      }
    }
    
  • 客户端访问代理角色

    public class Client(){
      public static void main(String[] args){
        Landlord landlord = new Landlord();
        //房东注入到中介中
        Proxy proxy = new Proxy(landlord);
        //你不用面对房东,直接找中介租房即可
        proxy.rent();
      }
    }
    

代理模式的好处:

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

缺点:

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

10.2、AOP实现机制

在这里插入图片描述

10.3、动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的
  • 底层使用反射实现
  • 动态代理分为两大类
    • 基于接口的动态代理:JDK动态代理【我们在这里使用】
    • 基于类的动态代理:cglib
    • Java字节码实现:Javassist

需要了解两个类:

  • Proxy:调用其静态方法newProxyInstance()生成实例
  • InvocationHandler:调用处理程序

InvocationHandlerjava.lang.reflect下的一个接口

  1. 动态代理类:
public class ProxyInvocationHandler implements InvocationHandler{
  //被代理的接口
  private Object target;
  
  public void setTarget(Object target){
    this.target = target;
  }
  
  //生成得到代理类
  public Object getProxy(){
    //需要传入类加载器,代理的接口和InvocationHandler
    return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
  }
  
  //处理代理实例,并返回结果
  public Object invoke(Object proxy, Method method,Object[] args) throw Throwable{
    log(method.getName());
    Object result = method.invoke(target, args);
    return result;
  }
  
  public void log(String msg){
    System.out.Println("执行了" + msg + "方法");
  }
}

2.实现类:

public class Client{
  public static void main(String[] args){
    //真实角色
    UserServiceImpl userService = new UserServiceImpl();
    //代理角色,不存在
    ProxyInvocationHandler pih = new ProxyInvocationHandler();
    //设置要代理的对象
    pih.setTarget(userService);
    //动态生成代理类
    UserService proxy = (UserSErvice)pih.getProxy();
    proxy.query();
  }
}

动态代理的好处:

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

11、AOP

11.1、什么是AOP

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

在这里插入图片描述

11.2、Aop在Spring中的作用

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

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

在这里插入图片描述

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

在这里插入图片描述

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

11.3、使用Spring实现Aop

环境配置:

  1. 使用AOP织入,需要导入一个依赖包

    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.4</version>
    </dependency>
    
方法一:使用springAPI接口(主要spring接口实现)

1.编写UserService和UserServiceImpl

package com.wang.service;

public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void select();
}
package com.wang.service;

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 select() {
        System.out.println("查询了一个用户");
    }
}

2.编写log类

在这里插入图片描述

package com.wang.log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;


public class Log implements MethodBeforeAdvice {

    //method:要执行的目标对象的方法
    //args:参数
    //target:目标对象
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName() + "的" + method.getName() + "被执行了");
    }
}

package com.wang.log;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class AfterLog implements AfterReturningAdvice {

    //returnValue:返回值
    public void afterReturning(Object returnValue, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("执行了" + method.getName() + "方法,并且返回了" + returnValue);
    }
}

3.编写配置文件ApplicationContext.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"
       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-->
    <bean id="userService" class="com.wang.service.UserServiceImpl"/>
    <bean id="log" class="com.wang.log.Log"/>
    <bean id="afterLog" class="com.wang.log.AfterLog"/>

    <!--方法一:使用原生的Spring API接口-->
    <!--配置AOP:需要导入AOP约束-->
    <aop:config>
        <!--切入点   expression表达式  execution(要执行的位置)-->
        <aop:pointcut id="pointcut" expression="execution(* com.wang.service.UserServiceImpl.*(..))"/>

        <!--执行环绕增加-->
        <aop:advisor advice-ref="log" pointcut-ref="pointcut" />
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    </aop:config>
</beans>

4.编写测试类

import com.wang.service.UserService;
import com.wang.service.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        //动态代理代理的是接口
        UserService userService = (UserService) context.getBean("userService");

        userService.add();
    }
}

测试结果:

在这里插入图片描述

在这里插入图片描述

execution 完整参数:(修饰符 返回值 包名.类名/接口名.方法名(参数列表))

(…)可以代表所有参数,()代表一个参数,(,String)代表第一个参数为任何值,第二个参数为String类型.

方法二:自定义来实现(主要是切面定义)

1.自定义类

package com.wang.diy;

public class DiyPointCut {


    public void before(){
        System.out.println("方法执行前");
    }
    public void after(){
        System.out.println("方法执行后");
    }
}

2.ApplicationContext.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"
       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-->
    <bean id="userService" class="com.wang.service.UserServiceImpl"/>
    <bean id="log" class="com.wang.log.Log"/>
    <bean id="afterLog" class="com.wang.log.AfterLog"/>

    <!--方法二:自定义类-->
    <bean id="diy" class="com.wang.diy.DiyPointCut"/>
    <aop:config>
        <!--自定义切面 ref要引用的类-->
        <aop:aspect ref="diy">
            <!--切入点-->
            <aop:pointcut id="point" expression="execution(* com.wang.service.UserServiceImpl.*(..))"/>
            <!--通知-->
            <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>
</beans>
方法三:使用注解实现(方法简单,但功能有限)

1.新建一个注解类

//方法三:使用注解方式实现AOP
@Aspect //标注这个类是一个切面
public class AnnotationPointCut {


    @Before("execution(* com.wang.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("方法执行前");
    }

    @After("execution(* com.wang.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("方法执行后");
    }
    //在环绕增强中,我们可以给定一个参数,到表我们要获取切入的点
    @Around("execution(* com.wang.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Annotation环绕前");
        System.out.println("获得签名" + joinPoint.getSignature());
        //执行方法
        Object proceed = joinPoint.proceed();
        System.out.println("Annotation环绕后");

    }
}

2.ApplicationContext.xml注册Bean并且开启注解

<!--方法三-->
    <bean id="annotationpointcut" class="com.wang.diy.AnnotationPointCut"/>
    <!--开启注解支持-->
    <aop:aspectj-autoproxy/>

12、整合MyBatis

12.1、环境配置

步骤:

  1. 导入相关jar包

    1.Junit

    2.MyBatis

    3.MySQL数据库

    4.Spring相关

    5.AOP织入

    6.MyBatis-spring【新包】

 <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.4</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.0.2.RELEASE</version>
        </dependency>
        <!--spring操作数据库的话,还需要的一个spring-jdbc的依赖-->
        <dependency>
            <groupId>org,springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.0</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.1</version>
        </dependency>
    </dependencies>

​ 7.编写配置文件

​ 8.测试

12.2、回忆MyBatis

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

12.3、MyBatis-spring

12.3.1、什么是MyBatis-Spring

MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。它将允许 MyBatis 参与到 Spring 的事务管理之中,创建映射器 mapper 和 SqlSession 并注入到 bean 中,以及将 Mybatis 的异常转换为 Spring 的 DataAccessException。最终,可以做到应用代码不依赖于 MyBatis,Spring 或 MyBatis-Spring。

在这里插入图片描述

12.3.2、环境配置

1.ApplicationContext.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"
       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">

    <!--DataSource:使用Spring的数据源替换MyBatis的配置 c3p0 dbcp druid-->
    <!--这里使用Spring提供的jdbc-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3307/mybatis?serverTimezone=UTC&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;useSSL=false"/>
        <property name="username" value="root"/>
        <property name="password" value="password"/>
    </bean>

    <!--sqlSessionFactory 可以替换所有的mybatis-config.xml里面的配置-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!--绑定MyBatis配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/wang/mapper/*.xml"/>
    </bean>

    <!--SqlSessionTemplate:就是我们使用的sqlSession-->
    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
        <!--只能使用构造器注入sqlSessionFactory,因为它没有set方法-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

    <bean id="userMapperImpl" class="com.wang.mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSessionTemplate"/>
    </bean>

    <bean id="userMapperImpl2" class="com.wang.mapper.UserMapperImpl2">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>
</beans>

2.UserMapper

public interface UserMapper {
    public List<User>  selectUser();
}

3.UserMapperImpl

public class UserMapperImpl implements UserMapper {
    //我们的所有操作与拿来都使用sqlSession
    //现在我们都使用sqlSessionTemplete

    private SqlSessionTemplate sqlSession;
    private SqlSessionTemplate sqlSessiont;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    public List<User> selectUser() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();
    }

    public void setSqlSessiont(SqlSessionTemplate sqlSessiont) {
        this.sqlSessiont = sqlSessiont;
    }

    public SqlSessionTemplate getSqlSessiont() {
        return sqlSessiont;
    }
}

UserMapperImpl2

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
    public List<User> selectUser() {
        SqlSession sqlSession = getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();
    }
}

4.UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:绑定一个对应的Dao(Mapper)接口-->
<mapper namespace="com.wang.mapper.UserMapper">
    <!--id对应对应Mapper接口的方法名字-->
    <select id="selectUser" resultType="com.wang.pojo.User" resultMap="UserMap">
        select * from mybatis.user
    </select>

    <resultMap id="UserMap" type="com.wang.pojo.User">
        <!--column表示字段,property表示实体类属性-->
        <result column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="pwd" property="pwd"/>
    </resultMap>
</mapper>

5.测试

public class MyTest {
    @Test
    public void test() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream in = Resources.getResourceAsStream(resource);

        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(in);

        SqlSession sqlSession = build.openSession(true);
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.selectUser();
        for (User user : userList) {
            System.out.println(user);
        }
    }

    @Test
    public void test2(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        UserMapper userMapper = applicationContext.getBean("userMapperImpl2", UserMapper.class);
        for (User user : userMapper.selectUser()) {
            System.out.println("user = " + user);
        }
    }
}

13、声明式事务

  1. 回顾事务
    • 要么都成功,要么都失败
    • 事务在项目开发中十分重要,涉及到数据的一致性问题
    • 确保完整性和一致性的关键
  2. 事务的ACID原则:(面试会问)
    • 原子性
    • 一致性
    • 隔离性:多个业务可能操作同一个资源,互相隔离不影响正确性。防止数据损坏
    • 持久性:事务一旦完成,无论系统发生如何变故,结果都不会再被影响,被持久化写到存储器中

13.1、Spring中的事物管理

  • 声明式事务:AOP横切
  • 编程式事务:代码中事务管理

13.2、案例

在这里插入图片描述

1.ApplicationContext.xml

<!--创建声明事务管理对象-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <constructor-arg ref="dataSource" />
    </bean>

    <!--结合AOP实现声明式事务织入-->
    <!--配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--给哪些方法配置事务-->
        <!--配置事务的传播特性 propagation-->
        <tx:attributes>
            <tx:method name="add" propagation="REQUIRED"/>
            <tx:method name="delete" propagation="REQUIRED"/>
            <tx:method name="update" propagation="REQUIRED"/>
            <tx:method name="query" read-only="true"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!--配置事务切入-->
    <aop:config>
        <aop:pointcut id="txPointCut" expression="execution(* com.neil.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config>

2.UserMapperImpl

public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {
    //我们的所有操作与拿来都使用sqlSession


    @Override
    public List<User> selectUser() {

        User user = new User(6, "张三三", "123123");
        UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
        mapper.addUser(user);
        mapper.deleteUser(6);
        return mapper.selectUser();
    }

    @Override
    public int addUser(User user) {
        return getSqlSession().getMapper(UserMapper.class).addUser(user);
    }

    @Override
    public int deleteUser(int id) {
        return getSqlSession().getMapper(UserMapper.class).deleteUser(id);
    }
}

正确性。防止数据损坏

  • 持久性:事务一旦完成,无论系统发生如何变故,结果都不会再被影响,被持久化写到存储器中

13.1、Spring中的事物管理

  • 声明式事务:AOP横切
  • 编程式事务:代码中事务管理

13.2、案例

[外链图片转存中…(img-MMkLP9Bm-1599130682146)]

1.ApplicationContext.xml

<!--创建声明事务管理对象-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <constructor-arg ref="dataSource" />
    </bean>

    <!--结合AOP实现声明式事务织入-->
    <!--配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--给哪些方法配置事务-->
        <!--配置事务的传播特性 propagation-->
        <tx:attributes>
            <tx:method name="add" propagation="REQUIRED"/>
            <tx:method name="delete" propagation="REQUIRED"/>
            <tx:method name="update" propagation="REQUIRED"/>
            <tx:method name="query" read-only="true"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!--配置事务切入-->
    <aop:config>
        <aop:pointcut id="txPointCut" expression="execution(* com.neil.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config>

2.UserMapperImpl

public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {
    //我们的所有操作与拿来都使用sqlSession


    @Override
    public List<User> selectUser() {

        User user = new User(6, "张三三", "123123");
        UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
        mapper.addUser(user);
        mapper.deleteUser(6);
        return mapper.selectUser();
    }

    @Override
    public int addUser(User user) {
        return getSqlSession().getMapper(UserMapper.class).addUser(user);
    }

    @Override
    public int deleteUser(int id) {
        return getSqlSession().getMapper(UserMapper.class).deleteUser(id);
    }
}
### 回答1: 狂神SpringCloud是一个专为微服务架构而设计的开源框架,它基于Spring Boot构建,提供了一系列解决微服务开发中常见问题的工具和组件。以下是对狂神SpringCloud代码的解析。 首先,在狂神SpringCloud代码中,我们会看到各种Spring Cloud的核心组件,如服务注册中心、服务提供者和服务消费者。其中,服务注册中心使用的是Eureka,它负责将各个服务的实例注册到自己的服务列表中,并提供给服务消费者访问。服务提供者是一个独立的服务,它会在启动时将自己注册到Eureka中,并提供特定的API接口供其他服务调用。服务消费者通过Eureka的服务发现功能找到需要调用的服务,并通过RestTemplate或Feign等工具进行调用。 其次,狂神SpringCloud代码中还会涉及到配置中心,它可以集中管理各个微服务应用的配置信息。常用的配置中心组件Spring Cloud Config和Nacos。在代码中,我们会看到配置中心的相关配置和注解,用于指定配置中心的地址和应用的配置文件名等信息。 此外,狂神SpringCloud代码中还会涉及到服务网关,它充当了整个微服务架构的入口,对外提供统一的API接口并进行鉴权、限流等操作。狂神SpringCloud常用的服务网关组件括Zuul和Gateway。通过配置网关的路由规则,可以将外部请求转发到对应的微服务上。 最后,狂神SpringCloud还提供了其他一些实用的组件,如断路器、消息总线和分布式锁等,用于增强微服务应用的容错性、可靠性和并发处理能力。 总而言之,狂神SpringCloud代码用于构建和管理微服务架构,通过各种组件和工具,实现了服务注册与发现、配置管理、服务网关、容错处理和分布式系统管理等功能。在实际开发中,可以根据具体需求选择适合的组件和配置,快速搭建弹性、可扩展的微服务体系。 ### 回答2: 狂神SpringCloud代码是由Java编写的一套基于Spring Cloud微服务架构的代码框架。狂神是一个知名的Java技术博主,他在Spring Cloud领域有丰富的经验和深入的理解,所以他的代码框架非常具有参考价值。 狂神SpringCloud代码提供了一种简洁而高效的方式来构建分布式系统。它含了一系列常用的微服务组件和工具,例如服务注册与发现、负载均衡、服务调用、断路器等。这些组件和工具的设计思想都符合Spring Cloud的原则和实践,可以帮助开发人员快速搭建和部署分布式应用。 狂神SpringCloud代码还提供了一套完善的文档和示例,可以帮助开发人员快速入门和上手。代码框架中的每个组件和工具都有详细的使用说明和示例代码,开发人员可以根据自己的需求进行配置和扩展。 狂神SpringCloud代码在实际应用中已经得到了广泛的验证和应用。它的设计理念和实现方式都非常成熟和稳定,可以在大规模并发和高可用的环境下运行。此外,狂神还提供了持续更新和升级的保障,确保代码框架始终跟上最新的技术发展。 总的来说,狂神SpringCloud代码是一套优秀的基于Spring Cloud的微服务代码框架,可以帮助开发人员快速搭建和部署分布式系统。它具有丰富的功能和强大的性能,并且有完善的文档和示例,易于学习和使用。如果你正在进行Spring Cloud项目,可以考虑使用狂神SpringCloud代码,它会为你的开发工作带来很大的便利和效率。 ### 回答3: 狂神Spring Cloud代码是指由狂神团队所开发和维护的Spring Cloud项目的代码。Spring Cloud是一个基于Spring Framework的开源微服务框架,它提供了一系列开发和管理分布式系统的工具。狂神团队在该项目的开发中贡献了大量的代码。 狂神Spring Cloud代码具有以下特点: 1. 高性能和可伸缩性:狂神Spring Cloud代码经过优化,能够高效运行并处理大量的请求。它支持水平扩展,可以根据需求增加或减少实例数量,以满足不同规模的业务需求。 2. 具备灵活的架构设计:狂神Spring Cloud代码采用松耦合的架构设计,各个组件之间通过接口进行通信,可以灵活组合和替换。这使得系统更加灵活和可维护,可以根据实际需求快速调整和扩展系统功能。 3. 提供丰富的功能模块:狂神Spring Cloud代码提供了丰富的功能模块,括注册中心、服务发现、配置中心、负载均衡、断路器等。这些模块可以帮助开发人员更快速地实现微服务架构,并提供了很多功能的默认实现,降低了开发难度。 4. 提供全面的监控和管理工具:狂神Spring Cloud代码提供了全面的监控和管理工具,可以监控系统的运行状态和性能指标,帮助开发人员快速定位和解决问题。同时,还提供了可视化的管理界面,方便管理人员对系统进行配置和管理。 总之,狂神Spring Cloud代码是一个高性能、可伸缩和灵活的微服务框架,提供了丰富的功能模块和监控管理工具,帮助开发人员快速构建和管理分布式系统。它的诞生对于推动微服务架构的发展和应用具有重要意义。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值