spring整理


概念

官网:https://spring.io

Spring makes Java simple, modern, productive, reactive, cloud-ready.

Spring是一个开源的轻量级的一站式框架。其核心为:

  • AOP:面向切面编程。简单理解面向切面编程,就是扩展功能不需要修改源代码;
  • IOC:控制反转。创建对象不再需要New来创建,而是交由Spring去创建;

之所以说Spring是一站式框架,是因为spring在javaee三层框架中都提供了不同技术:

  • web层:springMVC;
  • service层:主要使用spring的ioc;
  • dao层:提供了jdbcTemplate;

IOC原理及入门案例

Spring中IOC操作有两种方式:xml配置方式注解方式

Spring中ioc的实现底层主要依赖四种技术:

  • xml配置文件;
  • dom4j解析配置文件;
  • 工厂设计模式;
  • 反射;

现假如有UserService,内有add方法,要在Servlet中调用该方法,ioc伪代码实现:

// UserService
public class UserService {
  public void add(){};
}

// 1. 创建xml配置文件,配置对象类
<bean id="userService" class="cn.demo.UserService" />
  
// 2. 创建工厂类,类中使用dom4j加反射得到UserService实例
public class UserServiceFactory {
  public static UserService getUserServie(){
    // 3. 使用dom4j解析xml,根据id得到class的值
    // String classValue = "class属性值";
    // 4. 使用反射创建实例
    Class clazz = Class.forName(classValue);
    UserService userService = clazz.newInstance();
    return userService;
  }
}

// 使用工厂得到实例,调用方法即可

spring IOC入门案例:

  1. 引入依赖;
  2. 创建类和方法;
  3. 创建spring配置文件;
  4. 编码测试;

引入依赖:这里为IOC入门体验,因此只需引入spring核心包即可,包括Beans、Core、Context、SpEL。

<?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>cn.adoredu</groupId>
    <artifactId>spring-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
</project>

创建类:

package cn.adoredu.ioc;

public class UserService {

    public void add() {
        System.out.println("add...");
    }
}

创建spring配置文件,建议放至src下并叫applicationContext.xml:

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

    <bean id="userService" class="cn.adoredu.ioc.UserService"></bean>

</beans>

测试代码:

package cn.adoredu.ioc;

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

public class TestIOC {

    @Test
    public void test() {
        // 1. 加载配置文件,创建对象
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 2. 得到配置创建的对象
        UserService userService = (UserService) context.getBean("userService");

        // 查看结果
        System.out.println(userService);
        userService.add();
    }
}

Spring的bean管理(xml方式)

  1. Bean实例化的三种方式:
  • 使用无参数构造创建
<!-- 实际开发中最常用的实例化方式,上述配置实例化bean就是使用无参构造创建,如果类中没有无参构造函数会报错`No default constructor found;`,无法实例化对象;-->
<bean id="userService" class="cn.adoredu.ioc.UserService"></bean>
  • 使用静态工厂创建
// 创建静态方法工厂类
package cn.adoredu.ioc;

public class BeanFactory {
    
    // 静态方法
    public static UserService getUserService() {
        return new UserService();
    }
}
<?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="userService" class="cn.adoredu.ioc.UserService"></bean> -->

    <!-- 方式二:使用静态工厂创建 -->
    <bean id="userService" class="cn.adoredu.ioc.BeanFactory" factory-method="getUserService"></bean>

</beans>
  • 使用实例工厂创建
package cn.adoredu.ioc;

public class BeanFactory2 {

    // 普通方法
    public UserService getUserService() {
        return new UserService();
    }
}
<?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="userService" class="cn.adoredu.ioc.UserService"></bean> -->

    <!-- 方式二:使用静态工厂创建 -->
    <!-- <bean id="userService" class="cn.adoredu.ioc.BeanFactory" factory-method="getUserService"></bean> -->

    <!-- 方式三:使用实例工厂创建 -->
    <bean id="beanFactory" class="cn.adoredu.ioc.BeanFactory2"></bean>
    <bean id="userService" factory-bean="beanFactory" factory-method="getUserService"></bean>

</beans>
  1. Bean标签常用属性
  • id:bean标识, 可以任意,但不能包含特殊字符;

  • class:要创建对象所在类的全路径;

  • name:和id作用一样,但可以包含特殊字符。版本遗留问题,现一般使用id即可;

  • scope:

    • singleton:默认值,单实例;
    • prototype:多实例;
    • request:创建对象,把对象放在request域里面;
    • session:创建对象,把对象放在session域里面;
    • globalSession:创建对象,把对象放在globalSession域里面;

    理解singleton和prototype,多次调用context.getBean()方法得到的对象是同一个还是多个。

  1. 属性注入

属性注入是指在创建对象实例时,给其属性设置值。

给普通类设置属性值一般有三种方式:

  • 使用set方法注入:
public class User {
  private String name;
  public void setName(String name) {
    this.name = name;
  }
}
  • 使用构造方法注入:
public class User {
  private String name;
  public User(String name) {
    this.name = name;
  }
}
  • 使用接口注入:
public Interface UserDao {
  void setName(String name);
}

...
public class User Implenments UserDao {
  private String name;
  public void setname(String name) {
    this.name = name;
  }
}

spring中属性注入主要有两种方式:

  • set方法注入(常用)
package cn.adoredu.ioc.bean;

public class User {

    private String name;

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

    public void show() {
        System.out.println(this.name);
    }
}

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

    <!-- 使用set方法注入属性 -->
    <bean id="user" class="cn.adoredu.ioc.bean.User">
        <property name="name" value="Jerry"></property>
    </bean>

</beans>
package cn.adoredu.ioc;

import cn.adoredu.ioc.bean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestIOC {

    @Test
    public void test() {
        // 1. 加载配置文件,创建对象
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 2. 得到配置创建的对象
        User user = (User) context.getBean("user");
      
        user.show();
    }
}
  • 有参数构造注入
// 实体类
package cn.adoredu.ioc.bean;

public class User {

    private String name;

    public User(String name) {
        this.name = name;
    }
  
    public void show() {
      System.out.println(this.name);
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 使用有参构造注入属性 -->
    <bean id="user" class="cn.adoredu.ioc.bean.User">
        <constructor-arg name="name" value="Tom"></constructor-arg>
    </bean>

</beans>

使用set方式注入对象类型:

package cn.adoredu.ioc;

public class UserDao {

    public void add() {
        System.out.println("userDao add...");
    }
}
package cn.adoredu.ioc;

public class UserService {

    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void add() {
        System.out.println("userService add...");
        userDao.add();
    }
}
<?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">

    <!-- 使用set方式注入对象类型 -->
    <bean id="userDao" class="cn.adoredu.ioc.UserDao"></bean>
    <bean id="userService" class="cn.adoredu.ioc.UserService">
        <property name="userDao" ref="userDao"></property>
    </bean>

</beans>

使用set方式注入复杂类型:

package cn.adoredu.ioc;

import java.util.List;
import java.util.Map;
import java.util.Properties;

public class UserService {

    private String[] arrs;
    private List<String> list;
    private Map<String, String> map;
    private Properties properties;

    public void setArrs(String[] arrs) {
        this.arrs = arrs;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    public void add() {
        System.out.println("arrs:"+arrs);
        System.out.println("list:"+list);
        System.out.println("map:"+map);
        System.out.println("properties:"+properties);
    }
}

<?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="userService" class="cn.adoredu.ioc.UserService">
        <property name="arrs">
            <list>
                <value>java</value>
                <value>python</value>
            </list>
        </property>

        <property name="list">
            <list>
                <value>vue</value>
                <value>react</value>
            </list>
        </property>

        <property name="map">
            <map>
                <entry key="a" value="aa"></entry>
                <entry key="b" value="bb"></entry>
            </map>
        </property>

        <property name="properties">
            <props>
                <prop key="c">cc</prop>
                <prop key="d">dd</prop>
            </props>
        </property>
    </bean>

</beans>

Spring的bean管理(注解方式)

引入依赖:

<?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>cn.adoredu</groupId>
    <artifactId>spring-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>

        <!--使用注解需要spring-aop-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </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"
       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="cn.adoredu.anno"></context:component-scan>

    <!-- 只会扫描属性上注解 -->
    <!-- <context:annotation-config></context:annotation-config>-->

</beans>
  1. 注解创建对象
package cn.adoredu.anno;

import org.springframework.stereotype.Component;

@Component(value = "user")  // 相当于<bean id="user" class=""></bean>
//@Component("user") 属性为value时可以省略
//@Scope(value = "prototype")
public class User {

    public void add() {
        System.out.println("add...");
    }
}

测试:

package cn.adoredu.anno;

import cn.adoredu.anno.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestANNO {

    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        User user = (User) context.getBean("user");

        System.out.println(user);
        user.add();
    }
}
  1. 注解方式注入属性
package cn.adoredu.anno;

import org.springframework.stereotype.Component;

@Component("userDao")
public class UserDao {

    public void add() {
        System.out.println("userDao add...");
    }
}
package cn.adoredu.anno;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("userService")
public class UserService {

    @Autowired
    private UserDao userDao;
    // 注解方式不需要定义set方法

    public void add() {
        System.out.println("userServive add...");
        userDao.add();
    }
}

说明:@Autowired是通过类型注入,即与UserDao上@Component的value值无关。还可以通过@Resource方式注入属性,此时name属性值必须为对象的@Component的value值:@Component(name=”userDao”)。

IOC和DI

IOC:Inversion of Control,控制反转,把对象的创建交由spring管理;

DI:Dependency Injection,依赖注入,给类的属性设置值;

DI需要在IOC的基础上完成。

AOP原理

APP底层使用动态代理方式实现。分两种情况:

  • 有接口:使用jdk动态代理,创建接口实现类的代理对象;
  • 无接口:使用cglib动态代理,创建类的子类的代理对象;

AOP操作术语

  • JoinPoint:连接点。一个类中所有可以被增强的方法都称为连接点;
  • PointCut:切入点。类中真正被增强的方法叫切入点;
  • Advice:增强,也叫通知。指实际扩展的逻辑,分为
    • 前置通知:方法前执行;
    • 后置通知:方法后执行;
    • 异常通知:异常时执行;
    • 最终通知:后置之后执行;
    • 环绕通知:之前和之后,如统计方法执行时间时;
  • Aspect:切面。指把增强应用到切入点(的过程);

Spring的aop操作(xml方式)

Spring里使用aspectJ实现aop的操作。AspectJ本身不是Spring的一部分,它是一个面向切面的框架。Spring2.0以后增加了对AspectJ的支持。

使用AspectJ实现aop有两种方式:

  • 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>cn.adoredu</groupId>
    <artifactId>spring-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>

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

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.0.4.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

创建类:

package cn.adoredu.aop;

import org.aspectj.lang.ProceedingJoinPoint;

public class BookAdvice {

    public void before() {
        System.out.println("前置增强");
    }

    public void after() {
        System.out.println("后置增强");
    }

    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("方法之前");

        joinPoint.proceed();

        System.out.println("方法之后");
    }
}

package cn.adoredu.aop;

public class Book {

    public void add() {
        System.out.println("add...");
    }
}

配置:

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

    <!-- 1. 配置对象 -->
    <bean id="book" class="cn.adoredu.aop.Book"></bean>
    <bean id="bookAdvice" class="cn.adoredu.aop.BookAdvice"></bean>

    <!-- 2. 配置aop操作 -->
    <aop:config>
        <!-- 2.1 配置切入点 -->
        <aop:pointcut id="pointCut" expression="execution(* cn.adoredu.aop.Book.*(..))"/>

        <!-- 2.2 配置切面 -->
        <aop:aspect ref="bookAdvice">
            <!-- 配置增强类型 -->
            <aop:before method="before" pointcut-ref="pointCut" />

            <aop:after-returning method="after" pointcut-ref="pointCut" />

            <aop:around method="around" pointcut-ref="pointCut" />
        </aop:aspect>

    </aop:config>

</beans>

常用的表达时:

  • execution(* cn.adoredu.aop.Book.add(..)):修饰符 方法全路径(任意参数);
  • execution(* cn.adoredu.aop.Book.*(..));
  • execution(* *.*(..));
  • execution(* save*(..))

Spring的aop操作(注解方式)

配置:

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

    <!-- 配置对象 -->
    <bean id="book" class="cn.adoredu.aop.Book"></bean>
    <bean id="bookAdvice" class="cn.adoredu.aop.BookAdvice"></bean>

    <!-- 开启aop操作 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

类:

package cn.adoredu.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class BookAdvice {

    @Before(value = "execution(* cn.adoredu.aop.Book.*(..))")
    public void before() {
        System.out.println("前置增强");
    }

    @AfterReturning("execution(* *.*(..))")
    public void after() {
        System.out.println("后置增强");
    }

    @Around("execution(* *.*(..))")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("方法之前");

        joinPoint.proceed();

        System.out.println("方法之后");
    }
}

JdbcTemplate基本操作

添加依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>4.2.4.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>4.2.4.RELEASE</version>
</dependency>

<!-- 别忘了数据库驱动 -->
<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<version>5.1.9</version>
</dependency>

步骤:

  1. 创建对象,设置数据库信息;
  2. 创建jdbcTemplate对象,设置数据源;
  3. 调用jdbcTemplate对象里方法实现操作;

测试类:

package cn.adoredu.jdbc;

import cn.adoredu.ioc.bean.User;
import org.junit.Before;
import org.junit.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

public class TestJDBC {

    private JdbcTemplate jdbcTemplate;

    @Before
    public void init() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql:///spring-test");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");

        jdbcTemplate = new JdbcTemplate(dataSource);
    }

    @Test
    public void testInsert() {
        String sql = "INSERT INTO user VALUES (?, ?, ?)";
        int rows = jdbcTemplate.update(sql, 1, "admin", "123456");
        System.out.println(rows);
    }

    @Test
    public void testUpdate() {
        String sql = "UPDATE user SET password=? WHERE username=?";
        int rows = jdbcTemplate.update(sql, "654321", "admin");
        System.out.println(rows);
    }

    @Test
    public void testDelete() {
        String sql = "DELETE FROM user WHERE username=?";
        int rows = jdbcTemplate.update(sql, "admin");
        System.out.println(rows);
    }

    @Test
    public void testQuery() {
        // 查询返回一个值
        String sql = "SELECT COUNT(*) FROM user";
        int count = jdbcTemplate.queryForObject(sql, Integer.class);
        System.out.println(count);
    }

    @Test
    public void testQuery2() {
        // 查询一个对象
        String sql = "SELECT * FROM user WHERE username=?";
        User user = jdbcTemplate.queryForObject(sql, new MyRowMapper(), "admin");
        System.out.println(user);
    }

    @Test
    public void testQuery3() {
        // 查询返回对象list
        String sql = "SELECT * FROM user";
        List<User> userList = jdbcTemplate.query(sql, new MyRowMapper());
        System.out.println(userList);
    }
}

class MyRowMapper implements RowMapper<User> {

    public User mapRow(ResultSet resultSet, int i) throws SQLException {
        // 1. 从结果集中得到数据
        String username = resultSet.getString("username");
        String password = resultSet.getString("password");

        // 2. 把数据封装到对象
        User user = new User();
        user.setUsername(username);
        user.setPassword(password);

        return user;
    }
}

使用jdbcTemplate和dbutils非常类似。不同的是查询时的RowMapper需要手动实现。

Spring中配置jdbcTemplate

以使用c3p0连接池为例:

添加依赖:

<dependency>
    <groupId>c3p0</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.1.1</version>
</dependency>

实际上就是要把数据源的代码(如下)放在配置文件,交由Spring来创建(使用c3p0连接池):

ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql:///spring-test");
dataSource.setUser("root");
dataSource.setPassword("123456");
<?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"
       xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 配置c3p0连接池 -->
    <bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="dbc:mysql:///spring-test"></property>
        <property name="user" value="root"></property>
        <property name="password" value="123456"></property>
    </bean>

    <bean id="userService" class="cn.adoredu.c3p0.UserService">
        <property name="userDao" ref="userDao"></property>
    </bean>

    <bean id="userDao" class="cn.adoredu.c3p0.UserDao">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="datasource"></property>
    </bean>

</beans>

Spring中配置事物

Spring中使用事物有两种方式:编程式事物声明式事物,常用的是声明式事物。而声明式事物有xml配置和注解两种实现方式。

Spring中实现事物需要配置事务管理器。Spring对不同的dao层框架提供了不同的事物管理器接口(PlatformTransactionManager)实现类,对jdbcTemplate提供的实现类为DataSourceTransactionManager。

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

    <!-- 配置c3p0连接池 -->
    <bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql:///spring-test"></property>
        <property name="user" value="root"></property>
        <property name="password" value="123456"></property>
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="datasource"></property>
    </bean>

    <bean id="orderService" class="cn.adoredu.tx.OrderService">
        <property name="orderDao" ref="orderDao"></property>
    </bean>

    <bean id="orderDao" class="cn.adoredu.tx.OrderDao">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>

    <!-- 1. 配置事物管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"></property>
    </bean>

    <!-- 2. 配置事物增强 -->
    <!-- 指定事物管理器 -->
    <tx:advice id="transactionInterceptor" transaction-manager="transactionManager">
        <!-- 事物操作 -->
        <tx:attributes>
            <!-- 设置事物操作的方法匹配规则 -->
            <tx:method name="account*" />
        </tx:attributes>
    </tx:advice>

    <!-- 3. 配置切入点和切面 -->
    <aop:config>
        <!-- 切入点 -->
        <aop:pointcut id="pointcut" expression="execution(* cn.adoredu.tx.OrderService.*(..))"/>

        <!-- 切面 -->
        <aop:advisor advice-ref="transactionInterceptor" pointcut-ref="pointcut" />
    </aop:config>

</beans>
  1. 注解实现事物
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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/context
        http://www.springframework.org/schema/context/spring-context.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">

    <!-- 配置c3p0连接池 -->
    <bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql:///spring-test"></property>
        <property name="user" value="root"></property>
        <property name="password" value="123456"></property>
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="datasource"></property>
    </bean>

    <bean id="orderService" class="cn.adoredu.tx.OrderService">
        <property name="orderDao" ref="orderDao"></property>
    </bean>

    <bean id="orderDao" class="cn.adoredu.tx.OrderDao">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>

    <!-- 1. 配置事物管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"></property>
    </bean>
    
    <!-- 2. 开启事物注解 -->
    <tx:annotation-driven transaction-manager="transactionManager" />

</beans>
package cn.adoredu.tx;

import org.springframework.transaction.annotation.Transactional;

// 3. 添加@Transactional注解
@Transactional
public class OrderService {

    private OrderDao orderDao;
    public void setOrderDao(OrderDao orderDao) {
        this.orderDao = orderDao;
    }

    public void account() {
        orderDao.reduceMoney();
        int a = 10 / 0;  // 模拟异常
        orderDao.addMoney();
    }
}

Spring管理Web项目原理

  • 服务器启动时会为每个项目创建一个ServletContext对象;
  • 使用监听器,监听在ServletContext对象创建时,加载配置文件,创建对象;
  • 把创建出的对象放在ServletContext域对象中(setAttribute()方法);
  • 获取对象时到ServletContext域对象中获取即可(getAttribute()方法);

Spring已经实现管理web项目方式(依赖spring-web包)。只需要在web.xml中进行配置:

...
<!-- 指定spring配置文件位置 -->
<context-param>
	<param-name>contextConfigLocation</param-name>
  <param-value>classpath: applicationContext.xml</param-value>
</context-param>

<!-- 配置监听器 -->
<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
...