Spring基本使用

Spring框架

1.什么是Spring

  • Spring是一个开放源码的设计层面的框架
  • 他解决的是业务层和其他各层的松耦合问题,因此面向接口编程的思想贯穿整个系统应用
  • Spring是源于2003年兴起的轻量级Java开发框架
  • 简单俩说Spring是一个分层JavaSE/EE full-stack轻量级开源框架

2.Spring特点(优点)

1.方便解耦合,简化开发

​ 通过Spring提供的IOC容器,我们可以将对象之间的依赖关系交给Spring进行控制,避免硬编码所造成的程序耦合。有了Spring用户不用再为了单例模式类,属性文件这些很底层的需求编写代码,更可以专注上层应用。

2.AOP编程的支持

​ 通过Spring提供AOP功能,方便面向切面的编程 ,将日志从代码解耦出来

3.IOC

​ 控制反转依赖关系的转移,以前都是依赖于实现,现在是依赖于抽象,核心思想就是面向接口编程。

4.容器

​ Spring提供了容器的功能,容器可以管理对象的生命周期,和对象中得依赖关系,写成一个xml的配置文件,在上面定义类对象的名字,是不是单例,以及设置和其他对象的依赖关系,容器启动的时候这些对象就会被实例化完成,依赖关系也建立好了

2.IOC对象的控制反转

1.什么是IOC

​ 控制反转,将创建对象和对象之间的调用过程,交给spring去管理

​ 使用IOC目的:为了降低耦合度

2.底层原理实现
xml解析,工厂模式,反射

配置创建的对象:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VzBjAZcA-1635732706234)(Spring.assets/image-20211024105424699.png)]

解决痛点:

​ 1.Impl接口实现类需要切换的时候需要修改代码,代码耦合度太强

解决方法:

​ 通过反射加载xml里面的类

具体代码

bean.xml文件

<beans>
    <bean id="userMySqlDao" class="com.baicai.dao.UserMySqlDaoImpl"></bean>
    <bean id="userOracleDao" class="com.baicai.dao.UserOracleDaoImpl"></bean>
</beans>

MyBeanFactory

package com.baicai.dao;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MyBeanFactory {

    private static Map<String,Object> map = new HashMap<>();

    /*使用到的时候就去加载配置文件
    * 将配置文件中配置好的类全部创建对象
    * 创建完成之后就,存起来
    * 当需要使用这个类的时候就直接获取就行
    * */
    static {
        /**从Resource中获取资源文件*/
        InputStream resourceAsStream = MyBeanFactory.class.getResourceAsStream("/beans.xml");

        /**解析xml   需要引入dom4j依赖*/
        SAXReader saxReader = new SAXReader();

        try {
            /**读取xml 创建文档对象*/
            Document doc = saxReader.read(resourceAsStream);

            /**获取根节点*/
            Element rootElement = doc.getRootElement();

            /**获取根节点中的子元素*/
            List<Element> beanList = rootElement.elements("bean");

            /**遍历每一个子节点*/
            for (Element element : beanList) {
                /**获取属性*/
                String id = element.attributeValue("id");
                String className = element.attributeValue("class");

                /**通过反射来创建对象*/
                Class clazz = Class.forName(className);

                /**创建对象*/
                Object obj = clazz.newInstance();

                /** 将创建好的对象放到map里面 */
                map.put(id,obj);
            }


        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    //根据传入的name获得相应的Class
    public static Object getBean(String name){
        return map.get(name);
    }
}

Impl实现类

package com.baicai.dao;

public class UserMySqlDaoImpl implements UserDao{
    @Override
    public void useSql() {
        System.out.println("使用的是MySql数据库");
    }
}

测试类

package com.baicai.web;


import com.baicai.dao.MyBeanFactory;
import com.baicai.dao.UserDao;

public class TestWeb {
    //从bean中获取对象
   public static UserDao userDao = (UserDao) MyBeanFactory.getBean("userMySqlDao");

    public static void main(String[] args) {
        userDao.useSql();
    }

}

IOC接口

1.IOC思想基于IOC容器完成,IOC容器的底层就是Spring的内部接口

2.spring提供了IOC容器的两种实现方式(两个接口)

​ (1)BeanFactory:IOC容器的基本实现,是使用Spring内部的接口,不提供给开发人员使用(懒汉单例,用的时候才创建)

​ (2)ApplicationContext:beanFactory接口的子接口,提供更加强大的功能,一般由开发人员进行使用(饿汉单例,直接创建)

//加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");

//获取创建的对象
context.getBean("user",User.class);

//调用方法
user.add();

​ (3)主要的实现类FileSystemXmlApplicationContext参数是电脑中的绝对路径,ClasspathXmlApplicationContext是自己写的xml文件中的类

3.Spring配置

引入依赖并且定义版本号–方便统一的修改

 <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <!--定义版本号   ${org.springframework.version}-->
        <spring.version>5.1.7.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <!-- Spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>
    </dependencies>

在resource目录下面创建文件application.xml

加入schema约束

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

向文件application.xml里面添加配置

<bean id="userdao" class="com.baicai.dao.UserMySqlImpl></bean>

Test类

package com.baicai.web;import com.baicai.dao.UserDao;import org.junit.Test;import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestSpring {    @Test    public void testSpring(){        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");        UserDao dao = (UserDao)classPathXmlApplicationContext.getBean("userdao");        dao.useSql();    }}

3.依赖注入DI(注入属性)

提前设置好属性,所有使用的地方从spring容器中获取的对象,都已经设置好了属性

创建了对象(通过set方法来注入的对象)

重点:给spring管理类当中依赖的属性,通过配置文件进行赋值的过程

前提:必须要有set方法 很重要!!!!!!!

1.无参构造后set注入

在application.xml文件中添加 将属性提前设置好了就是依赖注入(代码创建的时候调用的是无参构造,完成了对象的创建)

<bean id="user" class="com.baicai.test.User">        <!--依赖注入-->        <property name="id" value="1"></property>        <property name="userName" value="白菜"></property>        <property name="password" value="123456"></property></bean>

ps:id和name的区别,id中不能有特殊符号,name中可以有特殊符号

2.有参构造的使用

类:

public class Orders {    //属性    private String oname;    private String address;    //有参数构造    public Orders(String oname,String address) {        this.oname = oname;        this.address = address;    }  }

配置

<!--(2)spring方式:有参数构造注入属性--><bean id="orders" class="com.atguigu.spring5.Orders">    <constructor-arg name="oname" value="Hello"></constructor-arg>    <constructor-arg name="address" value="China!"></constructor-arg></bean>
3.注入空值和特殊符号
<bean id="book" class="com.atguigu.spring5.Book">    <!--1null-->    <property name="address">        <null/><!--属性里边添加一个null标签-->    </property>        <!--2)特殊符号赋值-->     <!--属性值包含特殊符号       a 把<>进行转义 &lt; &gt;       b 把带特殊符号内容写到CDATA      -->        <property name="address">            <value><![CDATA[<<南京>>]]></value>        </property></bean>
4.注入对象
<bean id="mysqlImpl" class="com.baicai.dao.UserMySqlDaoImpl"/><bean id="mysqlImpl" class="com.baicai.dao.UserOracleDaoImpl"/><bean id="UserServiceImpl" class="com.baicai.service.UserServiceImpl">      <property name="userDao" ref="mysqlImpl"/></bean>
5.基于XML方式注入内部bean和级联赋值

类关系

public class Dept {    private String dname;    public void setDname(String dname) {        this.dname = dname;    }}//员工类public class Emp {    private String ename;    private String gender;    //员工属于某一个部门,使用对象形式表示    private Dept dept;        public void setDept(Dept dept) {        this.dept = dept;    }    public void setEname(String ename) {        this.ename = ename;    }    public void setGender(String gender) {        this.gender = gender;    }}

xml配置文件

<!--内部bean-->    <bean id="emp" class="com.atguigu.spring5.bean.Emp">        <!--设置两个普通属性-->        <property name="ename" value="Andy"></property>        <property name="gender" value="女"></property>        <!--设置对象类型属性-->        <property name="dept">            <bean id="dept" class="com.atguigu.spring5.bean.Dept"><!--内部bean赋值-->                <property name="dname" value="宣传部门"></property>            </bean>        </property>    </bean>
6.数组和集合的注入

1.被引用的类

private class Adress{    private String name;}

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.bean.xml

都是依赖于set方法

<?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">            <bean id="adress" class="com.baicai.pojo.Address"/>    <bean id="student" class="com.baicai.pojo.Student">         <!-- 普通的属性注入-->         <property name="name" value="白菜" />                  <!-- Bean注入 ref -->         <property name="address" ref="address"/>                  <!-- 数组注入 -->         <property name="books">             <array>                 <value>红楼梦</value>                 <value>水浒传</value>                 <value>三国演义</value>             </array>         </property>                  <!-- list集合注入 -->         <property name="hobbys">             <list>                <value>听歌</value>                <value>跳舞</value>                <value>睡觉觉</value>             </list>         </propery>                  <!--Map集合注入-->         <property name="card">             <map>                <entry key="身份证" value="2341234"/>                <entry key="银行卡" value="zhonguosdfa"/>             </map         </property>                  <property name="games">             <set>                 <value>白菜吃吃吃</value>                 <value>秋秋胖胖胖</value>             </set>         </property>                  <property name="games">             <null></null>         </property>                  <property name="info">             <props>                 <prop key="学号">17120416</prop>                 <prop key="姓名">白菜</prop>             </props>                  </property>             </bean>    </beans>

4.测试类

public test MyTest{    public static void main(String[] args){        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");        Student student = (Student) context.getBean("student");        System.out.println(student.getAddress());    }}
7.注入配置文件中的属性(连接数据库为例)

属性文件

(1)创建外部属性文件,properties 格式文件,写数据库信息(jdbc.properties)

    prop.driverClass=com.mysql.jdbc.Driver    prop.url=jdbc:mysql://localhost:3306/userDb    prop.userName=root    prop.password=root

(2)把外部 properties 属性文件引入到 spring 配置文件中 —— 引入 context 名称空间

<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名称空间-->            <!--引入外部属性文件-->    <context:property-placeholder location="classpath:jdbc.properties"/>    <!--配置连接池-->    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">        <property name="driverClassName" value="${prop.driverClass}"></property>        <property name="url" value="${prop.url}"></property>        <property name="username" value="${prop.userName}"></property>        <property name="password" value="${prop.password}"></property>    </bean>    </beans>

4.Bean相关配置

1.名称和标识

id:使用了唯一的约束,不能包含特殊的字符

name:可以有特殊字符,不唯一,就是别名的意思

class:要写全路径

2.设置声明周期和方法

init-method : bean被初始化的方法

destory-method : bean被销毁的时候执行的方法(Bean是单例创建,工厂关闭)

在bean标签中写上 属性

<bean id="user" class="com.baicai.User" init-method="myinit"   destory-method="mydestroy"></bean>

在User里面写上myinit 和 mydestroy方法

当调用applicationContext.close()的时候调用destory-method的方法

3.Bean的作用范围 也是在bean标签中配置 标签scope
singleton 默认的会使用单例来创建对象 使用getBean都是单例的
prototype 使用多例创建的对象 让对象变成多例

设置 scope 值是 prototype 时候,不是在加载 spring 配置文件时候创建对象,在调用 getBean 方法时候创建多实例对象

<bean id="book" class="com.atguigu.spring5.collectiontype.Book" scope="prototype"><!--设置为多实例-->        <property name="list" ref="bookList"></property></bean>

request 应用在web项目当中,Spring创建这个类之后,将这个对象存放到request范围当中

session 应用在web项目中 ,Spring创建这个类之后,将这个对象保存到session中

4.工厂的实例化方式

1.无参构造器实例化对象 通过无参构造

默认情况下都是spring通过调用无参构造器

2.静态工厂实例化对象

​ 在bean标签中添加factory-method=“createUser”

然后在需要实例化对象

public static void createUser(){    //相关业务}

3.创建一个对象的同时需要创建另外一个对象

<bean id="user1" class="com.baicai.User"></bean><bean id="user2" class="com.baicai.User" factory-bean="user1"></bean>

创建user2的时候user1就会被创建

5.返回不一样的bean

1、Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean(FactoryBean)

2、普通 bean:在配置文件中定义 bean 类型就是返回类型

3、工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样 第一步 创建类,让这个类作为工厂 bean,实现接口

public class MyBean implements FactoryBean<Course> {    //定义返回bean    @Override    public Course getObject() throws Exception {        Course course = new Course();        course.setCname("abc");        return course;    }}

xml文件

<bean id="myBean" class="com.atguigu.spring5.factorybean.MyBean"></bean>

实现类

@Testpublic void test3() { ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml"); Course course = context.getBean("myBean", Course.class);//返回值类型可以不是定义的bean类型! System.out.println(course);}
6.生命周期

(1)通过构造器创建 bean 实例(无参数构造)

(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)

(3)把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization

(4)调用 bean 的初始化的方法(需要进行配置初始化的方法)

(5)把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization

(6)bean 可以使用了(对象获取到了)

(7)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)

        public class Orders {         //无参数构造         public Orders() {         System.out.println("第一步 执行无参数构造创建 bean 实例");         }         private String oname;         public void setOname(String oname) {         this.oname = oname;         System.out.println("第二步 调用 set 方法设置属性值");         }         //创建执行的初始化的方法         public void initMethod() {         System.out.println("第三步 执行初始化的方法");         }         //创建执行的销毁的方法         public void destroyMethod() {         System.out.println("第五步 执行销毁的方法");         }        }

xml

public class MyBeanPost implements BeanPostProcessor {//创建后置处理器实现类    @Override    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {        System.out.println("在初始化之前执行的方法");        return bean;    }    @Override    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {        System.out.println("在初始化之后执行的方法");        return bean;    }}
@Test public void testBean3() {// ApplicationContext context =// new ClassPathXmlApplicationContext("bean4.xml"); ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml"); Orders orders = context.getBean("orders", Orders.class); System.out.println("第四步 获取创建 bean 实例对象"); System.out.println(orders); //手动让 bean 实例销毁 context.close(); }

xml

<!--配置文件的bean参数配置--><bean id="orders" class="com.atguigu.spring5.bean.Orders" init-method="initMethod" destroy-method="destroyMethod">	<!--配置初始化方法和销毁方法-->    <property name="oname" value="手机"></property><!--这里就是通过set方式(注入属性)赋值--></bean><!--配置后置处理器--><bean id="myBeanPost" class="com.atguigu.spring5.bean.MyBeanPost"></bean>

5.注解使用

1.基本步骤

创建maven工程

导入相应的依赖

在resource目录中创建application.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: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:component-scan base-package="com.baicai"></context:component-scan>    </beans>

扫描每个类上面有没有Component注解

package com.baicai.test;import lombok.Data;import org.springframework.stereotype.Component;@Data@Component("user")public class User {    private Integer id;    private String userName;    private String password;}

这样user就会被加载到IOC容器当中就能直接获得

package com.baicai.test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {    @org.junit.Test    public void testSpring(){        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");        User user = (User) applicationContext.getBean("user");        System.out.println(user);    }}
2.Spring 针对 Bean 管理中创建对象提供注解

(1)@Component

(2)@Service

(3)@Controller

(4)@Repository

3、基于注解方式实现对象创建

第一步 引入依赖 (引入spring-aop jar包

第二步 开启组件扫描

<!--开启组件扫描 1 如果扫描多个包,多个包使用逗号隔开 2 扫描包上层目录--><context:component-scan base-package="com.atguigu"></context:component-scan>

第三步 创建类,在类上面添加创建对象注解

//在注解里面 value 属性值可以省略不写,//默认值是类名称,首字母小写//UserService -- userService@Component(value = "userService") //注解等同于XML配置文件:<bean id="userService" class=".."/>public class UserService { public void add() { System.out.println("service add......."); }}

组件扫描的细节

<!--示例 1 use-default-filters="false" 表示现在不使用默认 filter,自己配置 filter context:include-filter ,设置扫描哪些内容--><context:component-scan base-package="com.atguigu" use-defaultfilters="false"> <context:include-filter type="annotation"expression="org.springframework.stereotype.Controller"/><!--代表只扫描Controller注解的类--></context:component-scan><!--示例 2 下面配置扫描包所有内容 context:exclude-filter: 设置哪些内容不进行扫描--><context:component-scan base-package="com.atguigu"> <context:exclude-filter type="annotation"expression="org.springframework.stereotype.Controller"/><!--表示Controller注解的类之外一切都进行扫描--></context:component-scan>

第四步 基于注解方式实现属性注入

(1)@Autowired:根据属性类型进行自动装配

第一步 把 service 和 dao 对象创建,在 service 和 dao 类添加创建对象注解

第二步 在 service 注入 dao 对象,在 service 类添加 dao 类型属性,在属性上面使用注解

@Servicepublic class UserService { //定义 dao 类型属性 //不需要添加 set 方法 //添加注入属性注解 @Autowired private UserDao userDao; public void add() { System.out.println("service add......."); userDao.add(); }}//Dao实现类@Repository//@Repository(value = "userDaoImpl1")public class UserDaoImpl implements UserDao {    @Override    public void add() {        System.out.println("dao add.....");    }}

(2)@Qualifier:根据名称进行注入,这个@Qualifier 注解的使用,和上面@Autowired 一起使用

//定义 dao 类型属性//不需要添加 set 方法//添加注入属性注解@Autowired //根据类型进行注入//根据名称进行注入(目的在于区别同一接口下有多个实现类,根据类型就无法选择,从而出错!)@Qualifier(value = "userDaoImpl1") private UserDao userDao

(3)@Resource:可以根据类型注入,也可以根据名称注入(它属于javax包下的注解,不推荐使用!)

//@Resource //根据类型进行注入@Resource(name = "userDaoImpl1") //根据名称进行注入private UserDao userDao;

(4)@Value:注入普通类型属性

@Value(value = "abc")private String name
4.完全注解开发

(1)创建配置类,替代 xml 配置文件

@Configuration //作为配置类,替代 xml 配置文件@ComponentScan(basePackages = {"com.atguigu"})public class SpringConfig {    }

(2)编写测试类

@Testpublic void testService2() { //加载配置类 ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); UserService userService = context.getBean("userService",UserService.class); System.out.println(userService); userService.add();}

6.IOC创建对象的方式

1.创建对象就会调用类的无参构造方法 —没有的话就会报错
2.假设我们要时候用有参构造对象

​ 1.下标赋值

<bean id="user" class="com.baicai.pojo.User">     <constructor-arg index="0" value="白菜"/></bean>

​ 2.类型赋值(不建议使用)

<bean id="user" class="com.baicai.pojo.User">     <constructor-arg type="java.lang.String" value="白菜"/></bean>

​ 3.通过参数名来设置

<bean id="user" class="com.baicai.pojo.User">    <construvtor-arg name="name" value="白菜" /></bean>

7.IOC注解详解

@component

修饰一个类,将这个类交给Spring管理 相当于在配置文件当中配置

<bean id=""  class="">

如果没有写id名字,默认把类名第一个字母小写,当作是id

@Component三个衍生的注解

为了更好的进行分层,Spring可以使用其他三个注解功能类似

@Controller 控制层

@Service service层

@Repository dao层

这三个注解其实就是Component名字不一样方便标识

属性注入

@Value 设置普通属性值 可以不用set方法

@Autowired 就是将Bean容器中的这个类的对象拿出来自动赋值给这个变量,使用byType实现

package com.baicai.dao;import lombok.Data;@Datapublic class People {    private String name;    @Autowired    private Dog dog;    @Autowired    private Cat cat;}

@Nullable 这个字段表示 这个注解可以为空 为空的情况下不报错

@Autowired(required = false) 如果定义了Autowired的required属性为false,说明这个属性为null,否则不许为空,使用byname实现

@Qualifier 和Autowired差不多 但是里面可以写名字指定到底是哪个类

解决痛点:在动态绑定的情况下多态可以接受很多个子类或者接口实现类 用name来指定

<bean id="cat111" class="com.baicai.Cat"/>
@Autowired@Qualifier(value="cat111")private Cat cat;

@Resoure就是将上面两个注释简写成一个,默认使用byName实现,如果找不到名字就byType实现

@scope 作用范围 取值singleton prototype request session globalsession

​ 放在类上面

7.单元测试

1.导入spring整合Junit坐标

        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-test</artifactId>            <version>5.0.2.RELEASE</version>        </dependency>

@PostConstruct 初始化方法

@PreDestroy销毁方法

8.Bean自动装配

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

在Spring中有三个自动装配方式

​ 1.在xml中显示的配置

​ 2.在java中显示配置

​ 3.隐的自动装配(bean)

8.1普通装配

people类:

package com.baicai.dao;import lombok.Data;@Datapublic class People {    private String name;    private Dog dog;    private Cat cat;}

宠物类

package com.baicai.dao;public class Dog {    public void shout(){        System.out.println("小狗叫");    }}
package com.baicai.dao;public class Cat {    public void shout(){        System.out.println("小猫喵喵喵");    }}

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"       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">        <bean id="dog" class="com.baicai.dao.Dog"/>    <bean id="cat" class="com.baicai.dao.Cat"/>        <bean id="people" class="com.baicai.dao.People">        <property name="cat" ref="cat"/>        <property name="dog" ref="dog"/>        <property name="name" value="白菜"/>    </bean></beans>

测试类

package com.baicai.test;import com.baicai.dao.People;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class test {    @Test    public void test(){        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");        People people =  context.getBean("people", People.class);        people.getCat().shout();        people.getDog().shout();    }}

8.2byName自动装配

自动部署就是在后面加 autowire=“byName”

Bean.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: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">        <bean id="dog" class="com.baicai.dao.Dog"/>    <bean id="cat" class="com.baicai.dao.Cat"/>        <bean id="people" class="com.baicai.dao.People" autowire="byName">        <property name="name" value="白菜"/>    </bean></beans>

ps:保证id唯一,并给bean需要和自动注入属性的set方法一致

8.3byType自动装配

相当于去找类就是class后面的东西

    <bean id="dog1111" class="com.baicai.dao.Dog"/>    <bean id="cat" class="com.baicai.dao.Cat"/>        <bean id="people" class="com.baicai.dao.People" autowire="byType">        <property name="name" value="白菜"/>    </bean>

ps:需要保证class唯一

9.使用Java的方式配置Spring

现在我们要完全不适用Sring的xml配置,全部交给Java来做

JavaConfig是Spring的子项目,在Spring之后变成了核心功能

配置类

package com.baicai.config;import com.baicai.pojo.User;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;@Configuration@ComponentScan("com.baicai")public class BaicaiConfig {    //就相当于我们之前写的一个Bean标签    //这个方法的名字就相当于bean标签中的id属性    // 这个方法的返回值就是标签中的class属性    @Bean    public User getUser(){        //这个就是返回注入bean的对象        return new User();    }}

user类

package com.baicai.pojo;import lombok.Data;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Component;@Data@Component@Import(baicai.class)public class User {    @Value("白菜")    private String name;}

测试类

import com.baicai.config.BaicaiConfig;import com.baicai.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 applicationContext = new AnnotationConfigApplicationContext(BaicaiConfig.class);        User getUser = applicationContext.getBean("user",User.class);        System.out.println(getUser.getName());    }}

10.代理模式(SpringAOP底层)

代理模式的分类:

静态代理模式

​ 角色分析:

​ 抽象角色: 一般会使用接口和抽象类来解决

package com.baicai.proxy.Dome1;//租房的人public interface Rent {    void RentHome();}

​ 真实角色:被代理的角色

package com.baicai.proxy.Dome1;//房东public class Host implements Rent {    @Override    public void RentHome() {        System.out.println("房东要出租房子");    }}

​ 代理角色: 代理的真实角色,代理真实的角色后会做一些附属操作

package com.baicai.proxy.Dome1;public class Proxy {    private Host host;    public Proxy(){    }    public Proxy(Host host){        this.host = host;    }    public void rent(){        //代理一般都有附属操作        seeHome();        host.RentHome();        fare();    }    public void seeHome(){        System.out.println("中介带我看房");    }    public void fare(){        System.out.println("收取中介费");    }}

​ 客户: 访问对象的人

package com.baicai.proxy.Dome1;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:调用处理程序

    InvocationHandler:是由代理实例的调用处理程序的接口

    每个代理实例都有一个关联的调用处理程序,在代理实例上调用方法的时候,方法调用并分配到调用处理程序的invoke方法

    核心工具类

    package com.baicai.proxy.Dome4;import com.baicai.proxy.Dome3.Rent;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;//等我们会使用这个类,自动生成代理类public class ProxyIvocationHandler implements InvocationHandler {    //被代理的接口    private Object target;    public void setRent(Object target){        this.target = target;    }    //生成得到代理类    public Object getProxy(){        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this);    }    //处理代理实例并且返回结果    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        //获取方法        log(method.getName());        //动态代理的本质就是使用反射机制实现        Object result = method.invoke(target, args);        return result;    }    public void log(String method){        System.out.println("调用了" + method + "方法");    }}
    

    调用主类

    package com.baicai.proxy.Dome4;import com.baicai.proxy.Dome2.UserService;import com.baicai.proxy.Dome2.UserServiceImpl;public class Client {    public static void main(String[] args) {        //真实角色        UserService userService = new UserServiceImpl();        ProxyIvocationHandler pih = new ProxyIvocationHandler();        pih.setRent(userService);        //动态生成代理类        UserService proxy = (UserService) pih.getProxy();        proxy.delete();    }}
    

ps:一个动态代理类代理的就是代理了一个接口

11.AOP

1.什么是AOP

面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一的维护技术,AOP是OOP的延续,是软件开发的一个热点,Spring框架中的的重要内容。

(1)面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得 业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

(2)通俗描述:不通过修改源代码方式,在主干功能里面添加新功能

(3)使用登录例子说明 AOP

在这里插å¥å›¾ç‰‡æè¿°

2.动态代理模式

a)AOP 底层使用动态代理 ,动态代理有两种情况:

第一种 有接口情况,使用 JDK 动态代理 ;创建接口实现类代理对象,增强类的方法

在这里插å¥å›¾ç‰‡æè¿°

第二种 没有接口情况,使用 CGLIB 动态代理;创建子类的代理对象,增强类的方法

img

3.动态代理的实现**(JDK 动态代理)**

1)使用 JDK 动态代理,使用 Proxy 类里面的方法创建代理对象

调用 newProxyInstance 方法,方法有三个参数:

public static Object newProxyInstance(ClassLoader loader,                                      Class<?>[] interfaces,                                      InvocationHandler h)

第一参数,类加载器

第二参数,增强方法所在的类,这个类实现的接口,支持多个接口

第三参数,实现这个接口 InvocationHandler,创建代理对象,写增强的部分

2)编写 JDK 动态代理代码

//(1)创建接口,定义方法public interface UserDao { public int add(int a,int b); public String update(String id);}
//(2)创建接口实现类,实现方法public class UserDaoImpl implements UserDao { @Override public int add(int a, int b) { return a+b; } @Override public String update(String id) { return id; }}
//(3)使用 Proxy 类创建接口代理对象public class JDKProxy { public static void main(String[] args) { //创建接口实现类代理对象 Class[] interfaces = {UserDao.class}; UserDaoImpl userDao = new UserDaoImpl(); /** 第一参数,类加载器 	第二参数,增强方法所在的类,这个类实现的接口,(支持多个接口)	第三参数,实现这个接口 InvocationHandler,创建代理对象,写增强的部分  */ UserDao dao =(UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces,					new UserDaoProxy(userDao)); int result = dao.add(1, 2); System.out.println("result:"+result); }}//创建代理对象代码class UserDaoProxy implements InvocationHandler { //1 把创建的是谁的代理对象,把谁传递过来 //有参数构造传递 private Object obj; public UserDaoProxy(Object obj) { this.obj = obj; } //增强的逻辑 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //方法之前 System.out.println("方法之前执行...."+method.getName()+" :传递的参数..."+ Arrays.toString(args)); //被增强的方法执行 Object res = method.invoke(obj, args); //方法之后 System.out.println("方法之后执行...."+obj); return res; }}
  • 横切关注点:跨越应用程序多个模块的方法或者功能。即与我们业务没有关系,但是我们需要关注的部分是横切关注点

  • 切面:横街关注点被模块化的特殊对象,它就是一个类

  • 通知:切面必须要完成的工作,就是切面中的一个方法

  • 目标:被通知的对象

  • 代理:向目标对象应用通知之后创建的对象

  • 切入点: 切面通知执行的低点的定义

  • 连接点:与切入点匹配的执行点

11.2 使用Spring的API接口

1.导入依赖
<properties>        <maven.compiler.source>8</maven.compiler.source>        <maven.compiler.target>8</maven.compiler.target>        <spring.version>5.1.7.RELEASE</spring.version>    </properties>    <dependencies>        <dependency>            <groupId>junit</groupId>            <artifactId>junit</artifactId>            <version>4.12</version>        </dependency>        <!-- Spring -->        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-context</artifactId>            <version>${spring.version}</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-beans</artifactId>            <version>${spring.version}</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-jdbc</artifactId>            <version>${spring.version}</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-aspects</artifactId>            <version>${spring.version}</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-context-support</artifactId>            <version>${spring.version}</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-test</artifactId>            <version>${spring.version}</version>        </dependency>        <!-- 接口包  -->        <dependency>            <groupId>org.aspectj</groupId>            <artifactId>aspectjweaver</artifactId>            <version>1.9.4</version>        </dependency>    </dependencies>

userService

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

userServiceImpl

package com.baicai.service;import org.springframework.stereotype.Component;@Componentpublic class UserServiceImpl implements UserService{    @Override    public void add() {        System.out.println("增加了一个用户");    }    @Override    public void delete() {        System.out.println("删除");    }    @Override    public void update() {        System.out.println("改变");    }    @Override    public void select() {        System.out.println("查找");    }}

Log类

package com.baicai.log;import org.springframework.aop.MethodBeforeAdvice;import java.lang.reflect.Method;public class Log implements MethodBeforeAdvice {    //method:要执行目标对象的方法    //args:参数    //target:目标参数    @Override    public void before(Method method, Object[] objects, Object o) throws Throwable {        System.out.println(o.getClass().getName() + "的" + method.getName() +"被执行了");    }}

AfterLog类

package com.baicai.log;import org.springframework.aop.AfterReturningAdvice;import java.lang.reflect.Method;public class AfterLog implements AfterReturningAdvice {    @Override    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {        System.out.println("执行了" +method.getName() + "返回结果为" + o);    }}

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"       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/aop        http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">    <context:component-scan base-package="com.baicai"/>    <!--注册bean-->    <bean id="userService" class="com.baicai.service.UserServiceImpl"/>    <bean id="log" class="com.baicai.log.Log"/>    <bean id="afterLog" class="com.baicai.log.AfterLog"/>    <!--配置aop:需要导入aop的约束-->    <aop:config>        <!-- 切入点: experssion表达式  execution(要执行的位置 * * * * * * *) -->        <!--第一个 * 代表可以是任意的位置 然后写上类名 第二个*代表所有的方法   (..)代表里面的参数-->        <aop:pointcut id="pointcut" expression="execution(* com.baicai.service.UserServiceImpl.*(..))"/>        <!--执行环绕增强-->        <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>    </aop:config></beans>

pom文件

<?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>org.example</groupId>    <artifactId>Spring-08-AOP</artifactId>    <version>1.0-SNAPSHOT</version>    <properties>        <maven.compiler.source>8</maven.compiler.source>        <maven.compiler.target>8</maven.compiler.target>        <spring.version>5.1.7.RELEASE</spring.version>    </properties>    <dependencies>        <dependency>            <groupId>junit</groupId>            <artifactId>junit</artifactId>            <version>4.12</version>        </dependency>        <!-- Spring -->        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-context</artifactId>            <version>${spring.version}</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-beans</artifactId>            <version>${spring.version}</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-jdbc</artifactId>            <version>${spring.version}</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-aspects</artifactId>            <version>${spring.version}</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-context-support</artifactId>            <version>${spring.version}</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-test</artifactId>            <version>${spring.version}</version>        </dependency>        <dependency>            <groupId>org.aspectj</groupId>            <artifactId>aspectjweaver</artifactId>            <version>1.9.4</version>        </dependency>    </dependencies>    <build>    <plugins>        <plugin>            <groupId>org.apache.maven.plugins</groupId>            <artifactId>maven-surefire-plugin</artifactId>            <version>2.4.2</version>            <configuration>                <skipTests>true</skipTests>            </configuration>        </plugin>    </plugins>    </build></project>

遇到问题

Failed to execute goal org.codehaus.mojo:exec-maven-plugin:3.0.0:exec (default-cli) on project

原因:idea 2020不兼容 不能使用main方法测试 要用test

方式2:自定义类来实现AOP

自定义com.baicai.diy.DiyPoint类

package com.baicai.diy;public class DiyPoint {    public void before(){        System.out.println("方法执行前");    }    public void after(){        System.out.println("方法执行后");    }}

bean.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"       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/aop        http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">    <context:component-scan base-package="com.baicai"/>    <bean id="userService" class="com.baicai.service.UserServiceImpl"/><bean id="diy" class="com.baicai.diy.DiyPoint"/>    <aop:config>        <!--自定义切面,ref的引用类-->        <aop:aspect ref="diy">            <!--切入点-->            <aop:pointcut id="point" expression="execution(* com.baicai.service.UserServiceImpl.*(..))"/>            <!--通知-->            <aop:before method="before" pointcut-ref="point"/>            <aop:after method="after" pointcut-ref="point"/>        </aop:aspect>    </aop:config></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"       xmlns:aop="http://www.springframework.org/schema/aop"       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/aop        http://www.springframework.org/schema/aop/spring-aop.xsd        http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">    <bean id="userService" class="com.baicai.service.UserServiceImpl"/>    <bean id="annotationPointCut" class="com.baicai.diy.AnnotationPointCut"/>    <!--自动代理-->    <aop:aspectj-autoproxy/></beans>

切面类

package com.baicai.diy;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;//标注这个类是一个切面@Aspectpublic class AnnotationPointCut {    @Before("execution(* com.baicai.service.UserServiceImpl.*(..))")    public void before(){        System.out.println("---方法执行前----");    }    @After("execution(* com.baicai.service.UserServiceImpl.*(..))")    public void after(){        System.out.println("方法执行后");    }    @Around("execution(* com.baicai.service.UserServiceImpl.*(..))")    public void around(ProceedingJoinPoint jp) throws Throwable {        System.out.println("环绕执行前");        Object proceed = jp.proceed();     //执行代理的方法        System.out.println("环绕执行后");    }}

测试类

import com.baicai.service.UserService;import com.baicai.service.UserServiceImpl;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class MyTest {    @Test    public void test() {        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");        UserService userService = (UserService) context.getBean("userService");        userService.add();    }}

12整合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>org.example</groupId>    <artifactId>Spring-09-mybatis</artifactId>    <version>1.0-SNAPSHOT</version>    <properties>        <maven.compiler.source>8</maven.compiler.source>        <maven.compiler.target>8</maven.compiler.target>    </properties>    <dependencies>        <dependency>            <groupId>org.Projectlombok</groupId>            <artifactId>lombok</artifactId>            <version>1.18.16</version>        </dependency>        <dependency>            <groupId>junit</groupId>            <artifactId>junit</artifactId>            <version>4.12</version>            <scope>test</scope>        </dependency>        <dependency>            <groupId>mysql</groupId>            <artifactId>mysql-connector-java</artifactId>            <version>5.1.47</version>        </dependency>        <dependency>            <groupId>org.mybatis</groupId>            <artifactId>mybatis</artifactId>            <version>3.5.2</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-jdbc</artifactId>            <version>5.1.7.RELEASE</version>        </dependency>        <dependency>            <groupId>org.aspectj</groupId>            <artifactId>aspectjweaver</artifactId>            <version>1.9.4</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-webmvc</artifactId>            <version>5.1.19.RELEASE</version>        </dependency>        <dependency>            <groupId>org.mybatis</groupId>            <artifactId>mybatis-spring</artifactId>            <version>2.0.2</version>        </dependency>    </dependencies>    <build>        <plugins>            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-surefire-plugin</artifactId>                <version>2.4.2</version>                <configuration>                    <skipTests>true</skipTests>                </configuration>            </plugin>        </plugins>        <resources>            <resource>                <!--需要扫描文件的目录-->                <directory>src/main/resources</directory>                <includes>                    <include>**/*.properties</include>                    <include>**/*.xml</include>                </includes>                <filtering>true</filtering>            </resource>            <resource>                <directory>src/main/java</directory>                <includes>                    <include>**/*.properties</include>                    <include>**/*.xml</include>                </includes>                <filtering>true</filtering>            </resource>        </resources>    </build></project>
  • junit
  • mybatis
  • mysql数据库
  • spring相关的
  • aop植入
  • mybatis-spring包

以上相关包导入

user类

package com.baicai.pojo;import lombok.Data;@Datapublic class User {    private int id;    private String name;    private String pwd;}

db.properties

jdbc.driver=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://192.168.10.151:3306/mybatis?charset=utf8&useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghaijdbc.username=rootjdbc.password=rootps::::不能直接使用username  因为username会调用idea的username产生冲突报错

编写数据源配置

<?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"><mapper namespace="com.baicai.mapper.UserMapper">    <select id="selectUser" resultType="user">        select * from mybatis.user    </select></mapper>

mybatis就可以专注起别名等设置配置

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configuration        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"        "http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration>        <typeAliases>        <package name="com.baicai.pojo"/>    </typeAliases>    <!--设置-->    <!--<settings>        <setting name="" value=""/>    </settings>--></configuration>

创建出sqlSessionFactory --专注Spring配置

<?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"       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/aop        http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context        https://www.springframework.org/schema/context/spring-context.xsd">    <context:property-placeholder location="classpath:db.properties"/>    <!--DataSource:使用Spring的数据源替换mybatis的配置        这里我们使用datasource提供的JDBC-->    <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">        <property name="driverClassName" value="${jdbc.driver}"></property>        <property name="url" value="${jdbc.url}"></property>        <property name="username" value="${jdbc.username}"></property>        <property name="password" value="${jdbc.password}"></property>    </bean>    <!--sqlSession-->    <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/baicai/mapper/*.xml"/>    </bean>    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">        <!--只能用构造器注入sqlSessionFactory,因为他没有Set方法-->        <constructor-arg index="0"  ref="sqlSessionFactory"/>    </bean></beans>

给接口加实现类 sqlSessionTemplate

package com.baicai.mapper;import com.baicai.pojo.User;import java.util.List;public interface UserMapper {    public List<User> selectUser();}
package com.baicai.mapper;import com.baicai.pojo.User;import lombok.Data;import org.mybatis.spring.SqlSessionTemplate;import java.util.List;@Datapublic class UserMapperImpl implements UserMapper{    //我们所有的操作都是sqlSession执行,现在使用SqlSessionTemplate    private SqlSessionTemplate sqlSession;    public void setSqlSessionTemplate(SqlSessionTemplate sqlSession) {        this.sqlSession = sqlSession;    }    @Override    public List<User> selectUser() {        UserMapper mapper = sqlSession.getMapper(UserMapper.class);        return mapper.selectUser();    }}

将自己写的实现类,注入到Spring中就行了

package com.baicai.test;import com.baicai.mapper.UserMapper;import com.baicai.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 context = new ClassPathXmlApplicationContext("applicationContext.xml");        UserMapper userMapper = context.getBean("userMapper", UserMapper.class);        for (User user : userMapper.selectUser()) {            System.out.println(user);        }    }}

整合Spring配置文件

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

    <import resource="spring-dao.xml"/>

    <bean id="userMapper" class="com.baicai.mapper.UserMapperImpl">
       <property name="sqlSession" ref="sqlSession"/>
   </bean>

</beans>

13.声明式事务

回顾事务

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

事务ACID原则

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

spring整合事务

1.事务添加到JavaEE三层结构里面的Service层

2.在Spring进行事务管理操作

有两种方式:编程式事务和声明式事务管理(使用)

3.声明式事务管理

(1)注解方式(常用)

(2) 使用xml文件方式

4.在Spring进行声明式事务管理,底层使用的是AOP

5.Spring事务管理API

(1) 提供了一个接口,代表事务管理器,这个接口针对不同的框架有不同的实现类

Spring事务管理提供了一个接口,叫做事务管理器,这个接口针对不同的框架提供不同的实现类

image-20210802191449867

对于使用JdbcTemplate进行数据库交互,则使用DataSourceTransactionManager实现类,如果整合Hibernate框架则使用HibernateTransactionManager实现类,具体情况具体使用

1)注解实现声明式事务管理:

<!-- 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
      destroy-method="close">
    <property name="url" value="jdbc:mysql://localhost:3306/book" />
    <property name="username" value="root" />
    <property name="password" value="000000" />
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
</bean>

<!--创建JdbcTemplate对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <!--注入数据库连接池-->
    <property name="dataSource" ref="dataSource"></property>
</bean>

<!--创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<!--开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

在service类上面或者service类的方法上面添加事务注解@Transactional

  • 如果把@Transactional添加在类上面,这个类里面所有方法都添加事务。
  • 如果只是添加在方法上面,则只为这个方法添加事务。
@Service
@Transactional
public class UserService {

声明式事务管理的参数配置:

propagation:事务传播行为,总共有7种

isolation:事务隔离级别

有三个读问题:脏读,不可重复读,虚读(幻读)。

设置隔离级别,解决读问题:

脏读不可重复读虚读
READ UNCOMMITED(读未提交)
READ COMMITED(读已提交)
REPEATABLE READ(可重复读)
SERIALIZABLE(串行化)

timeout:超时时间

  • 事务需要在一定时间内进行提交,超过时间后回滚。
  • 默认值是-1,设置时间以秒为单位。

readOnly:是否只读

  • 默认值为false,表示可以查询,也可以增删改。
  • 设置为true,只能查询。

rollbackFor:回滚,设置出现哪些异常进行事务回滚。

noRollbackFor:不回滚,设置出现哪些异常不进行事务回滚。

@Service 
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED) public class AccountService {

2)xml实现声明式事务管理:

<context:component-scan base-package="com.oymn"></context:component-scan>

<!-- 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
      destroy-method="close">
    <property name="url" value="jdbc:mysql://localhost:3306/book" />
    <property name="username" value="root" />
    <property name="password" value="000000" />
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
</bean>

<!--创建JdbcTemplate对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <!--注入数据库连接池-->
    <property name="dataSource" ref="dataSource"></property>
</bean>

<!--创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<!--配置事务通知-->
<tx:advice id="txadvice">
    <!--配置事务参数-->
    <tx:attributes>
        <tx:method name="accountMoney" propagation="REQUIRED" />
    </tx:attributes>
</tx:advice>

<!--配置切入点和切面-->
<aop:config>
    <!--配置切入点-->
    <aop:pointcut id="pt" expression="execution(* com.oymn.spring5.Service.*.*(..))"/>
    <!--配置切面-->
    <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
</aop:config>

14.整合日志

第一步:创建log4j2.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细输出-->
<configuration status="INFO">
    <!--先定义所有的appender-->
    <appenders>
        <!--输出日志信息到控制台-->
        <console name="Console" target="SYSTEM_OUT">
            <!--控制日志输出的格式-->
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </console>
    </appenders>
    <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
    <!--root:用于指定项目的根日志,如果没有单独指定Logger,则会使用root作为默认的日志输出-->
    <loggers>
        <root level="info">
            <appender-ref ref="Console"/>
        </root>
    </loggers>
</configuration>

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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
        ">



    <context:property-placeholder location="classpath:db.properties"/>

    <!--DataSource:使用Spring的数据源替换mybatis的配置
        这里我们使用datasource提供的JDBC-->
    <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

    <!--sqlSession-->
    <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/baicai/mapper/*.xml"/>
    </bean>

    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!--只能用构造器注入sqlSessionFactory,因为他没有Set方法-->
        <constructor-arg index="0"  ref="sqlSessionFactory"/>
    </bean>


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

    <!--结合AOP实现事务的织入-->

    <!--配置事务的类-->
    <tx:advice id="txtAdvice"  transaction-manager="transactionManager">
        <!--配置事务的传播特性-->
        <!--给那些方法配置事务-->
        <tx:attributes>
            <!--REQYUIRED如果没有事务就开启事务-->
            <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="txPoint" expression="execution(* com.baicai.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txtAdvice" pointcut-ref="txPoint"/>
    </aop:config>

</beans>

接口

package com.baicai.mapper;

import com.baicai.pojo.User;

import java.util.List;

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


    public int addUser(User user);

    public int deleteUser(int id);
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值