Spring之IOC

spring 的优势

Spring 是轻量级开源框架,以 IoC(Inverse Of Control:控制反转)和 AOP(Aspect Oriented Programming:面向切面编程)为内核。

  1. 降低了组件之间的耦合性 ,实现了软件各层之间的解耦
  2. 可以使用容易提供的众多服务,如事务管理,消息服务等
  3. 容器提供单例模式支持
  4. 容器提供了AOP技术,利用它很容易实现如权限拦截,运行期监控等功能
  5. spring对于主流的应用框架提供了集成支持,如hibernate,JPA,Struts等
  6. spring的DI机制降低了业务对象替换的复杂性

耦合和解耦

  1. 什么是耦合
    模块之间的关联关系
  2. 什么是解耦
    降低模块之间的联系
  3. 解耦目标
    在编译期不依赖,在运行时才依赖
  4. 解耦的思路
    • 通过反射创建对象,避免使用new创建对象
    • 将需要创建的类的全名称写到配置文件中

spring的组成

在这里插入图片描述
spring官网:现代化的java开发,说白就是基于spring的开发。
在这里插入图片描述

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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd">

<!--
    导入其他配置文件,

    到时候使用的时候加载这一个配置文件就可以
-->
   <import resource="beans.xml"/>

</beans>

ioc

<?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.lx</groupId>
    <artifactId>spring-study</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>spring-ioc</module>
    </modules>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>


    <dependencies>
<!--        导入springmvc就相当于导入了spring的各种包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>
    </dependencies>
</project>

ioc理论推导

传统的开发模式

package com.lx.dao;

public class MysqlJdbcDaoImpl implements JdbcDao{
    @Override
    public void success() {
        System.out.println("mysql connect success");
    }
}


package com.lx.dao;

public class OracleJdbcDaoImpl implements JdbcDao {
    @Override
    public void success() {
        System.out.println("oracle connect success");
    }
}



package com.lx.service;

import com.lx.dao.JdbcDao;
import com.lx.dao.MysqlJdbcDaoImpl;

public class JdbcServiceImpl implements JdbcService{

    private JdbcDao jdbcDao = new MysqlJdbcDaoImpl();

    @Override
    public void connectDatabase() {
        jdbcDao.success();
    }
}





package com.lx;

import com.lx.service.JdbcService;
import com.lx.service.JdbcServiceImpl;

public class JdbcTest {


    public static void main(String[] args) {

        /**
         * mysql connect success
         *
         * 现在我们连接mysql成功,如果我们想要连接oracle的话,
         * 就需要将JdbcServiceImpl中的
         * private JdbcDao jdbcDao = new MysqlJdbcDaoImpl();
         * 改为
         * private JdbcDao jdbcDao = new OracleJdbcDaoImpl();
         *
         * 这里只是两个数据库驱动(相当于需求),一旦多了,那就需要修改非常多的代码
         *
         * 我们需要解决这个问题
         *
         *
         */
        JdbcService jdbcService = new JdbcServiceImpl();

        jdbcService.connectDatabase();
    }

}

在上面的代码中,用户的需求(就是test)可能会影响我们原来的代码,我们需要根据用户的需求去修改源代码,如果程序代码量十分大,修改一次的成本代价十分昂贵。

我们使用一个set方法实现

之前,程序是主动创建对象!控制权在程序员手上。
使用了set注入之后,程序变成了被动的接受对象。控制权在用户手上。

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

就是说我们如果还要添加更多的数据库驱动,我们只需要添加该xxxJdbcDaoImpl,至于用户(test)使用哪个驱动,可以由用户决定。我们不再需要根据用户的需求来修改代码。

package com.lx.service;

import com.lx.dao.JdbcDao;

public class JdbcServiceImpl implements JdbcService{

    private JdbcDao jdbcDao;

	// 利用set进行动态值的注入
    public void setJdbcDao(JdbcDao jdbcDao) {
        this.jdbcDao = jdbcDao;
    }

    @Override
    public void connectDatabase() {
        jdbcDao.success();
    }
}





package com.lx;

import com.lx.dao.MysqlJdbcDaoImpl;
import com.lx.dao.OracleJdbcDaoImpl;
import com.lx.service.JdbcService;
import com.lx.service.JdbcServiceImpl;

public class JdbcTest {


    public static void main(String[] args) {

    

        JdbcService jdbcService = new JdbcServiceImpl();
//        mysql connect success
//        ((JdbcServiceImpl) jdbcService).setJdbcDao(new MysqlJdbcDaoImpl());
//        oracle connect success
        ((JdbcServiceImpl) jdbcService).setJdbcDao(new OracleJdbcDaoImpl());
        jdbcService.connectDatabase();
    }

}

ioc本质

ioc的作用,减少计算机程序的耦合(解除我们代码中的依赖关系)

之前我们使用对象基本通过new关键字,如果各模块都是这么创建对象,假如有一天我们需要修改这个类,那么跟着需要修改的模块可能会很多。

IOC利用java反射机制,设计模式用到了工厂模式。

在这里插入图片描述

在这里插入图片描述

HelloSpring

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd">

<!--
    使用spring来创建对象


    普通创建对象
    Hello hello = new Hello();

    spring创建对象
    id 变量名
    class new的对象
    property 相当于set
        使用property时该类必须有该属性的set方法
    name 给该对象起别名(,代表可以起多个别名,同时还可以用 ; 空格 进行分割)
-->
    <bean id="hello" class="com.lx.pojo.Hello" name="alias,alias2">
        <!-- collaborators and configuration for this bean go here -->
        <property name="str" value="spring"/>
    </bean>

    <bean id="mysqlJdbcDaoImpl" class="com.lx.dao.MysqlJdbcDaoImpl"/>
    <bean id="OracleJdbcDaoImpl" class="com.lx.dao.OracleJdbcDaoImpl"/>


    <bean id="jdbcServiceImpl" class="com.lx.service.JdbcServiceImpl">
<!--        ref 引用spring容器中创建好的对象
            value 具体的值
-->
        <property name="jdbcDao" ref="mysqlJdbcDaoImpl"/>
    </bean>



<!--    <bean id="..." class="...">-->
<!--        &lt;!&ndash; collaborators and configuration for this bean go here &ndash;&gt;-->
<!--    </bean>-->

    <!-- more bean definitions go here -->

</beans>
package com.lx.pojo;

public class Hello {

    private String str;

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }


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







package com.lx;

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

public class SpringBeanTest {

    public static void main(String[] args) {
        // 获取spring的上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        // 我们的对象现在都在spring中管理了,我们要使用的话,直接去里面取出来就可以了
        Hello hello = (Hello) context.getBean("hello");

        // hello对象是由spring创建的,hello对象的属性是由spring容器设置的
        System.out.println(hello.getStr());


    }
}

在这里插入图片描述

spring定义Bean的三种方式

xml方式

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

    <groupId>com.itheima</groupId>
    <artifactId>spring_study</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
</project>
<?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="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>

    <bean id="userService" class="com.itheima.service.impl.UserServiceImpl"></bean>
<!-- 默认是单例模式,prototype,多例模式-->
	<bean id="userService" class="com.itheima.service.impl.UserServiceImpl" scope="prototype"></bean>

	<!--初始化执行的方法,销毁时执行的方法-->
    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" init-method="init" destroy-method="destroy"></bean>

</beans>
package com.itheima.test;

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

public class SpringTest {



    @Test
    public void testSpringFactory(){

//        创建spring的IOC容器对象
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");

//       从容器中获取对象
        Object userDao = ioc.getBean("userDao");

        System.out.println(userDao);

    }
}

注解方式

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: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:组件,bean对象
        scan:扫描
        base-package:基础包,扫描指定的包及其子包

        扫描的类中只要标记了@Component注解都可以创建对象,一般在代码中是三个子注解

        @Controller 一般在表现层用
        @Service 一般在业务层用
        @Repository 一般在持久层用
        @Component 泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注
    -->
    <context:component-scan base-package="com.itheima"></context:component-scan>


</beans>
// @RestController
@Controller
@RequestMapping("product/attr")
public class AttrController {}


@Service("productAttrValueService")
public class ProductAttrValueServiceImpl {}

配置类方式

代码不对,主要是表达注解

package com.itheima.config;

import com.mysql.cj.jdbc.MysqlDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;

import javax.management.Query;
import javax.sql.DataSource;

@PropertySource({"classpath:jdbc.properties"})
public class JdbcConfig {


    @Value("${jdbc.url}")
    private String url;

    @Bean("queryRuner")
    public Query creatQuery(DataSource dataSource){
        Query query = new Query(dataSource);

        return query;

    }

    @Bean("dataSource")
    public DataSource createDataSource(){

        DataSource dataSource = new MysqlDataSource();
        return dataSource;
    }
}





package com.itheima.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

/**
 * @Configuration
 * 标记在类上,代表该类为配置文件,相当于 applicationContext.xml
 *
 * @ComponentScan
 * 开启注解扫描包
 *
 * @Import
 * 导入配置文件
 *
 * @Bean
 * 标记在方法上,该方法返回的对象会放到spring ioc容器中

	@Scope("singleton")
 */

@Configuration
@ComponentScan(basePackages = {"com.itheima"})
@Import({JdbcConfig.class})
public class SpringConfig {
}

spring的依赖注入(DI)

  • ioc默认是使用无参构造创建对象
  • 假设我们要使用有参构造创建对象

在创建对象的过程中Spring可以依据配置对象的属性进行设置,这个过程称之为依赖注入,也即DI

构造函数注入

<!--    ==============constructor 构造器注入(需要实体类有相应的构造器)=====================  -->

<!--    属性(参数名)注入-->
    <bean id="hello" class="com.lx.pojo.Hello">
        <constructor-arg name="str" value="spring"/>
        <constructor-arg name="age" value="111"/>
    </bean>


<!--    索引注入-->
    <bean id="hello2" class="com.lx.pojo.Hello">
        <constructor-arg index="0" value="python"/>
        <constructor-arg index="1" value="222"/>
    </bean>


    <!--    类型注入,不建议使用-->
    <bean id="hello3" class="com.lx.pojo.Hello">
        <constructor-arg type="java.lang.String" value="java"/>
        <constructor-arg type="int" value="333"/>
    </bean>

set 方法注入

pojo
实体类

package com.itheima.domain;

import java.util.*;

public class User {

    private Integer id;
    private String name;
    private Date date;

    private List<String> list;
    private String[] array;
    private Set<String> set;
    private Map<String,Object> map;
    private Properties properties;
	
	// setter getter ...

<?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只能给简单类型注入
		pojo需要ref
	-->
    <bean id="user" class="com.itheima.domain.User">

<!-- 普通属性注入 -->
        <property name="id" value="1"></property>
        <property name="name" value="zs"></property>
        <!-- bean注入,ref -->  
        <property name="date" ref="data"></property>
        <bean id="data" class="java.util.Date"></bean>


<!-- 集合属性注入 -->
		<property name="list">
            <list>
                <value>mybatis</value>
                <value>spring</value>
                <value>springmvc</value>
            </list>
        </property>

        <property name="array">
            <array>
                <value>springdata</value>
                <value>boot</value>
                <value>security</value>
            </array>
        </property>

        <property name="set">
            <set>
                <value>zs</value>
                <value>zs</value>
                <value>ls</value>
            </set>
        </property>


        <property name="map">
            <map>
                <entry key="name" value="ww"></entry>
            </map>
        </property>

        <property name="properties">
            <props>
                <prop key="sex"> nv</prop>
            </props>
        </property>

		<!-- 注入null -->
		<property name="properties">
            <null></null>
        </property>
        <!-- 注入空字符串 -->
        <property name="name" value=""></property>
    </bean>

</beans>

p命名空间和c命名空间(了解)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd">


<!--    p名称空间,通过set注入-->
    <bean id="hello" name="com.lx.pojo.Hello" p:name="java" p:age="18"/>

    <!--    c名称空间,通过构造器注入-->
    <bean id="hello" name="com.lx.pojo.Hello" c:name="java" c:age="18"/>

</beans>

spring bean的自动装配

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

在spring中有三种装配的方式

  1. 在xml中显示的配置
  2. 在java中显示配置(spring config)
  3. 隐式的自动装配bean(重要)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd ">


    <bean id="cat" class="com.lx.pojo.Cat"/>
    <bean id="dog" class="com.lx.pojo.Dog"/>


<!--    其中的cat dog是引用的上面的bean,我们需要手动将属性注入,是手动装配-->
<!--    <bean id="people" class="com.lx.pojo.People">-->
<!--        <property name="name" value="lx"/>-->
<!--        <property name="cat" ref="cat"/>-->
<!--        <property name="dog" ref="dog"/>-->
<!--    </bean>-->



<!--
    byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的 beanid
        public void setDog(Dog dog) {
        public void setCat(Cat dog) {

        如果改变bean id的值则会在容器上下文中找不到对象
        <bean id="cat222" class="com.lx.pojo.Cat"/>

    byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean(也就是Dog类型/Cat类型)

        如果有两个该类型的对象,则会在编译期间报错(该类的对象必须全局唯一)
        <bean id="cat222" class="com.lx.pojo.Cat"/>
        <bean id="cat333" class="com.lx.pojo.Cat"/>
-->


<!--    <bean id="people" class="com.lx.pojo.People" autowire="byName">-->
<!--        <property name="name" value="lx"/>-->
<!--    </bean>-->
    <bean id="people" class="com.lx.pojo.People" autowire="byType">
        <property name="name" value="lx"/>
    </bean>



</beans>
  • byname,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致。
  • bytype,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致。

使用注解实现自动装配

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import javax.annotation.Resource;

public class People {

    private String name;

    // 如果显示定义了Autowired的required属性为false,说明这个对象可以为null,否则不允许为null
//    @Autowired(required = false)
    @Autowired
    // @Qualifier 和 @Autowired 搭配使用
    // @Autowired默认按照类型注入,如果该类有多个对象,则需要指定该类的对象名称
    // 但通常来说用不到,因为spring的对象一般来说是单例的
    @Qualifier("cat22")
    private Cat cat;

    @Resource
    private Dog dog;





package com.lx;

//import com.lx.pojo.Hello;
import com.lx.pojo.People;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class SpringBeanTest {

    public static void main(String[] args) {
        // 获取spring的上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");


        // 我们的对象现在都在spring中管理了,我们要使用的话,直接去里面取出来就可以了
        People people = context.getBean("people",People.class);

        people.getDog().sout();
        people.getCat().sout();



    }
}

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

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

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

@Resource和@Autowired的区别

  1. 都是用来自动装配的,都可以放在属性字段上
  2. @Autowired是spring声明的,@Resource是jdk声明的
  3. @Autowired默认按照类型注入,如果类型有多个,则按照名称注入
    @Resource默认按照名称注入,如果没有该名称的对象,则按照类型注入,如果两个都找不到就报错
    (这里的名称和类型实际上就是指该类的对象的名称和该类)

bean对象作用域

作用范围

  1. singleton:单例的(默认值)
  2. prototype:多例,每次从容器中获取都会产生一个新的对象
  3. request:作用于web应用的请求范围,每次 http 请求都会创建一个新的 Bean
  4. session:作用于web应用的会话范围,同一个 http Session 共享一个 Bean ,不同的 http Session 使用不同的 Bean
  5. global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境时,它就是session
<bean id="hello" name="com.lx.pojo.Hello" scope="singleton"/>

作用范围的生命周期

  • 单例对象:scope=“singleton”
    一个应用只有一个对象的实例。它的作用范围就是整个引用。

    生命周期:
    对象出生:当应用加载,创建容器时,对象就被创建了。
    对象活着:只要容器在,对象一直活着。
    对象死亡:当应用卸载,销毁容器时,对象就被销毁了。

  • 多例对象:scope=“prototype”
    每次访问对象时,都会重新创建对象实例。

    生命周期:
    对象出生:当使用对象时,创建新的对象实例。
    对象活着:只要对象在使用中,就一直活着。
    对象死亡:当对象长时间不用,且没有别的对象引用时,被 java 的垃圾回收器回收了。

spring中单例模式和多例模式

单例:所有请求用同一个对象来处理。通过单例模式,可以保证系统中一个类只有一个实例。

多例:每个请求用一个新的对象来处理。

  • 单例模式(单例多线程的)
    优点:共享一个实例,内存占用少,GC开销小
    缺点:共享资源存在线程安全问题
  • 多例模式(单线程的)
    优点:不存在线程安全问题(静态共享资源除外)
    缺点:多个实例,内存占用多,GC开销大

简述单例bean的生命周期

一个对象的生命周期包括创建(实例化与初始化),使用以及销毁等阶段,在Spring中,Bean对象周期也遵循这一过程,但是Spring提供了许多对外接口,允许开发者对3个过程(实例化、初始化、销毁)的前后做一些操作,在Spring Bean中,实例化是为Bean对象开辟空间,初始化则是对属性的初始化。

  1. 实例化bean
  2. 为bean的属性设置值和对其他bean的引用
  3. 调用bean的初始化方法(如数据源赋值,校验属性等)
  4. 处理Awar接口
  5. 处理各种后置处理器,在初始化方法后的后置方法中会根据情况包装为代理类,即AOP
  6. 当容器关闭时,调用bean的销毁方法

初始化方法和销毁方法

public class Book {
    public void init(){
        System.out.println("初始化方法");
    }
    public void destroy(){
        System.out.println("销毁方法");
    }
}

// 1. xml方式
<bean id="book" class="com.xc.enity.Book" init-method="init" destroy-method="destroy" />

// 2. @Bean方式
@Bean(initMethod = "init",destroyMethod = "destroy")
public Book book(){
    return new Book();
}

// 3. 实现接口方式
public interface InitializingBean {
	void afterPropertiesSet() throws Exception;
}

public interface DisposableBean {
	void destroy() throws Exception;
}

// 4. 声明式注解 @PostConstruct(初始化)@PreDestroy(销毁)

// 初始化销毁顺序:声明式—>接口式—>自定义式
// 单例:容器关闭时候销毁;多例:容器关闭不销毁

BeanPostProcessor后置处理器

// 1. spring所有bean初始化前后都会执行后置处理器
// 2. 可以定义多个后置处理器,一旦返回null,则跳过之后的处理器往下执行了
// 3. 可以返回bean,也可以返回bean的包装对象(aop动态代理)

@Component
public class MyBeanPostProcessor 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;
    }
}

xxxAware接口

spring aware 目的为了让bean获取spring容器中的服务。

// BeanNameAware:获取容器中bean名称
// BeanFactorAware:获取BeanFactory容器
// ApplicationContextAware:获取应用上下文
// 属性填充后,后置处理器前执行

@Component
public class BeanUtil implements ApplicationContextAware {
    private ApplicationContext context;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }
    public Object getBean(String beanName){
        return context.getBean(beanName);
    }
}

mybatis-spring

在这里插入图片描述

回顾mybatis

<?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">
    <parent>
        <artifactId>spring-study</artifactId>
        <groupId>org.lx</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>spring-mybatis</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>


    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </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-webmvc</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>
<!--        spring操作数据库-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.2</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.28</version>
        </dependency>
    </dependencies>


    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
<!--                不写这个,就读取不到这些静态资源-->
                <includes>
                    <include>**/*.xml</include>
                    <include>**/*.properties</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>
</project>
jdbc.driver=com.mysql.cj.jdbc.Driver
# 这儿别加引号,会报驱动找不到
jdbc.url=jdbc:mysql://192.168.52.3:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false
jdbc.username=root
jdbc.password=root





<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration核心配置文件-->
<configuration>


    <!--    引入外部属性文件-->
    <properties resource="db.properties" />


    <!--    配置日志工厂,默认STDOUT_LOGGING-->
    <settings>
        <!--        是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
<!--        <setting name="logImpl" value="LOG4J"/>-->
    </settings>


    <typeAliases>
        <package name="com.lx.pojo"/>
    </typeAliases>


    <environments default="development">
        <environment id="development">
            <!--            mybatis默认的事务管理器是jdbc,默认的连接池是pooled-->
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--    每一个Mapper.xml都需要在mybatis核心配置文件中注册!-->
    <mappers>
        <package name="com.lx.mapper"/>
    </mappers>
</configuration>

package com.lx.mapper;

import com.lx.pojo.User;

import java.util.List;

public interface UserMapper {

    List<User> selectUser();
}





<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lx.mapper.UserMapper">
    <select id="selectUser" resultType="user">
        select * from user
    </select>

</mapper>
import com.lx.mapper.UserMapper;
import com.lx.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MyTest {

    @Test
    public void test() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");

        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = mapper.selectUser();
        System.out.println(users.toArray());

    }
}

整合mybatis方式一

#jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.driver=com.mysql.jdbc.Driver
# 这儿别加引号,会报驱动找不到
jdbc.url=jdbc:mysql://192.168.66.3:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false
jdbc.username=root
jdbc.password=root
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration核心配置文件-->
<configuration>

<!--    别名也可以在spring配置文件中配置-->
    <typeAliases>
        <package name="com.lx.pojo"/>
    </typeAliases>

</configuration>

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


<!--    引入外部配置文件-->
    <context:property-placeholder location="classpath:db.properties"/>

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


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

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

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

</beans>
package com.lx.mapper;

import com.lx.pojo.User;

import java.util.List;

public interface UserMapper {

    List<User> selectUser();
}



package com.lx.mapper;

import com.lx.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;

import java.util.List;

public class UserMapperImpl implements UserMapper{

    // 我们的所有操作都使用sqlSession来执行,现在都使用SqlSessionTemplate
    private SqlSessionTemplate sqlSessionTemplate;

    public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
        this.sqlSessionTemplate = sqlSessionTemplate;
    }

    @Override
    public List<User> selectUser() {
        UserMapper userMapper = sqlSessionTemplate.getMapper(UserMapper.class);
        return userMapper.selectUser();
    }
}




import com.lx.mapper.UserMapper;
import com.lx.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MyTest {

    @Test
    public void test() throws IOException {

        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring-dao.xml");
        UserMapper userMapper = classPathXmlApplicationContext.getBean("userMapperImpl", UserMapper.class);
        System.out.println(userMapper.selectUser());
    }
}


整合mybatis方式二

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


<!--    引入外部配置文件-->
    <context:property-placeholder location="classpath:db.properties"/>

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


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


<!--    第一种方式-->
<!--    SqlSessionTemplate:就是我们使用的sqlSession-->
<!--    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">-->
<!--&lt;!&ndash;        只能用构造器注入sqlSessionFactory,因为它没有set方法&ndash;&gt;-->
<!--        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>-->
<!--    </bean>-->

<!--    <bean id="userMapperImpl" class="com.lx.mapper.UserMapperImpl">-->
<!--        <property name="sqlSessionTemplate" ref="sqlSessionTemplate"/>-->
<!--    </bean>-->


<!--    第二种方式-->

    <bean id="userMapper" class="com.lx.mapper.UserMapperImpl2">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>

</beans>
package com.lx.mapper;

import com.lx.pojo.User;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{

    @Override
    public List<User> selectUser() {
        // 以下两种都可以
//        return getSqlSession().selectList("com.lx.mapper.UserMapper.selectUser");
        return getSqlSession().getMapper(UserMapper.class).selectUser();
    }
}

spring声明式事务

查询一般使用SUPPORTS,增删改用REQUIRED。

  • REQUIRED(默认)
    有事务加入事务,没有事务新建事务
  • SUPPORTS
    有事务在事务中运行,没有事务,非事务执行
<?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:tx="http://www.springframework.org/schema/tx"
       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/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd
            http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">


<!--    引入外部配置文件-->
    <context:property-placeholder location="classpath:db.properties"/>

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




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

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

<!--    结合aop实现事务的织入,配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--        给哪些方法配置事务-->
<!--        配置事务的新特性
                REQUIRED 默认
            是不是只有增删改需要配置事务,查需要配置么?这个暂时没答案
            下面的select在这儿只是为了测试用的
-->
        <tx:attributes>
            <tx:method name="add*"/>
            <tx:method name="insert*"/>
            <tx:method name="update*"/>
            <tx:method name="delete*"/>
            <tx:method name="select*"/>
        </tx:attributes>
    </tx:advice>

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


    <bean id="userTransactionMapper" class="com.lx.mapper.UserTransactionMapperImpl">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>
</beans>
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lx.mapper.UserTransactionMapper">
    <select id="insertUser" parameterType="user">
        insert into user values(#{id},#{name},#{pwd})
    </select>

    <select id="deleteUser" parameterType="int">
        delete from user where id = #{id}
    </select>

    <select id="selectUser" resultType="user">
        select * from user
    </select>



</mapper>

package com.lx.mapper;

import com.lx.pojo.User;

import java.util.List;

public interface UserTransactionMapper {

    void insertUser(User user);

    void deleteUser(int id);

    List<User> selectUser();

}



package com.lx.mapper;

import com.lx.pojo.User;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

public class UserTransactionMapperImpl extends SqlSessionDaoSupport implements UserTransactionMapper{


    @Override
    public void insertUser(User user) {

        getSqlSession().getMapper(UserTransactionMapper.class).insertUser(user);
    }

    @Override
    public void deleteUser(int id) {
        getSqlSession().getMapper(UserTransactionMapper.class).deleteUser(id);
    }


    public List<User> selectUser(){
        insertUser(new User(6,"赵晓辉","9999"));
        System.out.println(1/0);
        deleteUser(6);
        return getSqlSession().getMapper(UserTransactionMapper.class).selectUser();
    }
}






import com.lx.mapper.UserMapper;
import com.lx.mapper.UserTransactionMapper;
import com.lx.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MyTest {

    @Test
    public void test() throws IOException {

        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring-dao.xml");
        UserTransactionMapper userTransactionMapper = classPathXmlApplicationContext.getBean("userTransactionMapper", UserTransactionMapper.class);
        userTransactionMapper.selectUser();
    }
}

部分知识引用自:
https://www.bilibili.com/video/BV1WE411d7Dv?p=2&vd_source=64c73c596c59837e620fed47fa27ada7
https://blog.csdn.net/weixin_42476601/article/details/82454677
https://blog.csdn.net/weixin_43888891/article/details/109021817
https://blog.csdn.net/weixin_42383680/article/details/107955368
https://blog.csdn.net/qq_45326640/article/details/103875263
https://blog.csdn.net/qq_35512802/article/details/121234638

我们这个现代晚期的世界,是有史以来第一次认为所有人类应享有基本上的平等,然而我们可能正准备要打造出一个最不平等的社会。纵观历史,上层阶级总是说自己比下层阶级更聪明、更强壮,整体而言更为优秀。他们过去通常只是在自欺欺人,贫苦农家的孩子智力很可能和王子也相去不远。然而,在新一代医药推波助澜下,上层阶级的自命不凡可能即将成为一种客观事实。

人类简史

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值