首页 > 其他分享 >2020-5-23-Spring

2020-5-23-Spring

时间:2024-03-22 17:00:16浏览次数:25  
标签:23 Spring void springframework class 2020 org import public

简介、耦合、控制反转、依赖注入、注解方式反转控制和依赖注入、Spring整合Junit、银行转账案例、代理、AOP面向切面编程、JDBCTemplate

简介

1核心内容

IOC反向控制、AOP面向切面编程

2优势

方便解耦,简化编程

AOP编程支持

声明式事务支持

方便程序的测试

方便集成各种优秀的框架

降低JAVAEE API的使用难度

JAVA源码是经典的学习范例

3四大核心容器

Beans、Core、Context、SpEL


耦合

程序间的依赖关系称为耦合。解耦就是降低程序间的依赖关系。

1解耦案例一

DriverManager,registeDriver(new com.mysql.jdbc.Driver());
//编译依赖

class.forName("com.mysql.jdbc.Driver")
//运行依赖
    
//分析:如果删除掉com.mysql.jdbc.Driver文件,前者在编译时报错,后者在运行时报错

避免使用new关键字,通过读取配置文件来获取要创建对象的全类名,再使用反射来创建对象

2Bean的概念

Bean表示可重复使用的组件

JavaBean表示java语言编写的重复使用的组件

3工厂模式案例

1)Bean.properties

service1=services.service1

2)BeanFactory.java

package client;

import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Properties;

public class BeanFactory {
    static private Properties properties;
    static private HashMap<String,Object> map;
    static {
        try {
            //读取配置文件
            InputStream in=BeanFactory.class.getClassLoader ().getResourceAsStream ("Bean.properties");
            properties=new Properties ();
            properties.load (in);

            //创建实例并放入容器中
            Enumeration keys=properties.keys ();
            map=new HashMap<String, Object> ();
            while (keys.hasMoreElements ()){
                String key=keys.nextElement ().toString ();
                Object obj=Class.forName (properties.getProperty (key)).newInstance ();
                map.put (key,obj);
            }
        } catch (IOException e) {
            e.printStackTrace ( );
        } catch (IllegalAccessException e) {
            e.printStackTrace ( );
        } catch (InstantiationException e) {
            e.printStackTrace ( );
        } catch (ClassNotFoundException e) {
            e.printStackTrace ( );
        }
    }

    public static Object getBean(String beanname){
        return map.get (beanname);
    }
}

3)clientMain

package client;

import services.service1;

public class clientMain {

    public static void main(String[] args) {
        for (int i = 0; i <5 ; i++) {
            service1 s=(service1) BeanFactory.getBean ("service1");
            System.out.println (s);
            s.service ();
        }
    }
}
//执行的是同一个实例的方法

控制反转

把创建对象的权力交给框架,此过程称为控制反转,是框架的重要特性,包括依赖注入、依赖查找

1Spring IOC的基本使用

1)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.zhanghuan</groupId>
    <artifactId>sprignioc</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
        <dependency><!--导入相关依赖-->
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.5.RELEASE</version>
        </dependency>
    </dependencies>

</project>

2)beans配置文件

<?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="service1" class="services.service1"></bean>
</beans>

3)client.java

package client;

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

public class clientMain {

    public static void main(String[] args) {
        ApplicationContext ac=new ClassPathXmlApplicationContext ("beans.xml");
        //创建Bean对象方式一
        service1 s=(service1)ac.getBean ("service1");

        //创建Bean对象方式二
        service1 s1=ac.getBean ("service1",service1.class);

        //总之,通过xml文件配置的id获取bean
        
        s.service ();
        s1.service ();
    }
}

2ApplicationContext接口的3种实现类

实现类 传入配置文件特点
ClassPathXmlApplicationContext 配置文件在类路径下
FileSystemXmlApplicationContext 配置文件在磁盘任意未知
AnnotationConfigApplicationContext 无配置文件,配置信息通过注解设置

3核心容器的接口

接口名 特点
ApplicationContext 读取完配置文件,立即创建对象
BeanFactory 读取完配置文件,延迟创建对象

常用的是ApplicationContext,可自动根据不同情况实现单例或多例模式

4创建Bean的三种方式

1)默认构造函数创建

<!--省略部分代码-->
<bean id="service1" class="services.service1"></bean>

如果对象无默认构造函数,则无法创建实例

2)使用工厂普通方法创建

package services;
//这是工厂类
public class serviceFactory {
    service1 build_service(){
        return new service1 ();
    }
}
<!--省略部分代码-->
<bean id="serviceFactory" class="services.serviceFactory"></bean>
<bean id="service_from_factory1" factory-bean="serviceFactory" factory-method="build_service"></bean>

3)使用工厂静态方法创建

package services;
//这是工厂类
public class serviceStaticFactory {
    static service1 build_service(){
        return new service1 ();
    }
}
<!--省略部分代码-->
<bean id="serviceStaticFactory" class="services.serviceStaticFactory" factory-method="build_service"></bean>

5bean标签的scope属性

属性名 说明
singleton 单例
prototype 多例
request 作用于web应用的请求范围
session 作用于会话的请求范围
global-session 作用于集群会话的请求范围

依赖注入

依赖关系的维护交给spring来做,此过程称为依赖注入。(创建对象的过程中,将参数传入,参数可能是其他对象,使得对象间产生依赖)

1可注入的类

基本类型和String类型

其他bean(配置文件中配置过的或注解配置过的bean)

复合类型/集合类型

注意

经常变化的不要注入

2注入方式

1)构造方法注入

<bean id="student" class="doMain.Student">
        <constructor-arg name="id" value="1"></constructor-arg>
        <constructor-arg name="male" value="男"></constructor-arg>
        <constructor-arg name="name" value="zhanghuan"></constructor-arg>
        <constructor-arg name="math" value="95"></constructor-arg>
        <constructor-arg name="english" value="100"></constructor-arg>
</bean>

需要注意的是,doMain.Student类里必须要有对应参数的构造方法,否则无法注入,其本质是调用构造方法注入

constructor-arg标签的属性

属性 解释
type 要注入的参数的类型
index 要注入的参数的下标
name 要注入的参数的参数名
value 要注入的参数的值,支持字符串和数字
ref 要注入的参数的值,支持配置文件中的其他bean

2)setter方法注入

<bean id="student" class="doMain.Student">
        <property name="id" value="1"></property>
        <property name="male" value="男"></property>
        <property name="name" value="zhanghuan"></property>
        <property name="math" value="95"></property>
        <property name="english" value="100"></property>
</bean>

property 标签的属性

属性 解释
name 要注入的参数的参数名
value 要注入的参数的值,支持字符串和数字
ref 要注入的参数的值,支持配置文件中的其他bean

复杂类型通过setter方法注入

package doMain;

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

//目标bean
public class LoveYou {
    private List<Student> students;
    private Map<String,String> map;

    public List<Student> getStudents() {
        return students;
    }

    public void setStudents(List<Student> students) {
        this.students = students;
    }

    public Map<String, String> getMap() {
        return map;
    }

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

    @Override
    public String toString() {
        return "LoveYou{" +
                "students=" + students +
                ", map=" + map +
                '}';
    }
}

<bean id="loveyou" class="doMain.LoveYou">
        <property name="students">
            <list>
                <ref bean="student"/>
                <ref bean="student"/>
            </list>
        </property>
        <property name="map">
            <map>
                <entry key="name" value="zhanghuan"></entry>
            </map>
        </property>
</bean>

列表类型数据可选标签:list,array,set

键值对数据可选标签:map,props


注解方式反转控制和依赖注入

1xml方式和注解方式对比

功能 xml配置文件 注解
创建对象 bean标签 Component,Controller,Service,Repository
注入依赖(数据) property标签 Autowired,Quqlifier,Resource,Value
改变作用范围 scope属性 Scope
生命周期相关 init-method属性 Postconstruct
destroy-method属性 PreDestroy

2各注解功能

1)Component注解

用于把当前类对象存入spring容器中,属性value设置该bean的id,如果不设置默认为该类的小写名。Controller,Service,Repository和该注解的功能一样。

使用前需要在配置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="doMain"></context:component-scan>
    <!--扫描文件夹,将里的类实例化后放入容器-->
</beans>

2)注入bean

(1)Autowired注解

指定注入依赖,可配置在类的变量上,也可配置在类的方法上。在变量上配置该注解后,该变量的setter方法可省去。注入的前提是,容器中有唯一一个bean对象和要注入的变量类型匹配,否则导致注入失败而报错。

(2)Qualifier注解

不可以单独使用,必须和Autowored合用,value属性值设置注入bean的id

(3)Resource注解

可单独使用,name属性值设置注入bean的id

注意

以上3中方式只可注入bean类型,无法注入基本类型和String类型,集合类型只能通过xml方式注入

3)注入基本类型和String类型

Value注解

其value属性值为要注入的基本类型和String类型数据,可以使用spring中的SpEl表达式

4)Scope注解

其value属性值为singleton和prototype,控制类的使用方式是单例还是多例

5)生命周期相关注解

Postconstruct注解和PreDestroy注解,主要在单例模式下使用,value值为指定的类的构造方法和析构方法

3数据库增删改查案例

1)pom.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>org.zhanghuan</groupId>
    <artifactId>annotationspring</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

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


        <dependency>
            <groupId>commons-dbutils</groupId>
            <artifactId>commons-dbutils</artifactId>
            <version>1.4</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>

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

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>
    </dependencies>

</project>

2)StudentDaoImpl.java

package com.rootpackage.dao;

import com.rootpackage.doMain.Student;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;


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

@Repository("studentdao")
public class StudentDaoImpl implements StudentDao {
    @Autowired
    private QueryRunner runner;

    public void setRunner(QueryRunner runner) {
        this.runner = runner;
    }

    public void insertOne(Student student) {
        try {
            runner.update ("insert into student (male,name,math,english) values(?,?,?,?)",student.getMale (),student.getName (),student.getMath (),student.getEnglish ());
        } catch (SQLException e) {
            e.printStackTrace ( );
        }
    }

    public void deleteOne(int id) {
        try {
            runner.update ("delete from student where id=?",id);
        } catch (SQLException e) {
            e.printStackTrace ( );
        }
    }

    public void updateOne(Student student) {
        try {
            runner.update ("update student set male=?,name=?,math=?,english=? where id=?",student.getMale (),student.getName (),student.getMath (),student.getEnglish (),student.getId ());
        } catch (SQLException e) {
            e.printStackTrace ( );
        }
    }

    public Student findOne(int id) {
        try {
            return runner.query ("select * from student where id=?",new BeanHandler<Student> (Student.class),id);
        } catch (SQLException e) {
            throw new RuntimeException ();
        }
    }

    public List<Student> findAll() {
        try {
            return runner.query ("select * from student",new BeanListHandler<Student> (Student.class));
        } catch (SQLException e) {
            throw new RuntimeException ();
        }
    }
}

3)StudentServiceImpl.java

package com.rootpackage.services;

import com.rootpackage.dao.StudentDao;
import com.rootpackage.doMain.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository("studentserviceimpl")
public class StudentServiceImpl implements StudentService {
    @Autowired
    private StudentDao dao;

    public void insertOne(Student student) {
        dao.insertOne (student);
    }

    public void deleteOne(int id) {
        dao.deleteOne (id);
    }

    public void updateOne(Student student) {
        dao.updateOne (student);
    }

    public Student findOne(int id) {

        return dao.findOne (id);
    }

    public List<Student> findAll() {

        return dao.findAll ();
    }
}

4)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">
    <context:component-scan base-package="com.rootpackage"></context:component-scan>
    <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
        <constructor-arg name="ds" ref="datasource"></constructor-arg>
    </bean>
    <bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/test1?serverTimezone=UTC&amp;useUnicode=true&amp;characterEncoding=UTF-8"></property>
        <property name="user" value="root"></property>
        <property name="password" value=""></property>
    </bean>
</beans>

5)test01.java


import com.rootpackage.doMain.Student;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.rootpackage.services.StudentServiceImpl;

import java.util.List;


public class test01 {
    private StudentServiceImpl s=null;
    @Before
    public void init(){
        ApplicationContext ac=new ClassPathXmlApplicationContext ("beans.xml");
        s=ac.getBean ("studentserviceimpl",StudentServiceImpl.class);
    }

    @Test
    public void findal(){
        List<Student> list=s.findAll ();
        for (Student i:
                list) {
            System.out.println (i);
        }
    }

    @Test
    public void insertone(){
        Student student=new Student ();
        student.setMale ("男");
        student.setName ("sylvester");
        student.setMath (85);
        student.setEnglish (90);
        s.insertOne (student);
    }

    @Test
    public void deleteone(){
        s.deleteOne (13);
    }

    @Test
    public void updateone(){
        Student student=new Student ();
        student.setId (15);
        student.setMale ("男");
        student.setName ("sylvester1");
        student.setMath (85);
        student.setEnglish (90);
        s.updateOne (student);
    }

    @Test
    public void findone(){
        Student student=s.findOne (15);
        System.out.println (student);
    }
}

4配置类

1)Configuration注解

该注解标志的类表示是一个配置类

2)ComponentScan注解

指定创建容器扫描的包,value值为要扫描的包的位置

3)Bean注解

修饰方法,该方法的返回值将会被存入spring的ioc容器中

//注解配置方式创建容器
ApplicationContext ac=new AnnotationConfigApplicationContext (springConfig.class,jdbcConfig.class);//这里可传入多个字节码文件,传入的字节码文件对应的类的Configuration注解可省略
s=ac.getBean ("studentserviceimpl",StudentServiceImpl.class);
package config;

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


@Configuration
@ComponentScan("com.rootpackage")
public class springConfig {

}
package config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;

@Configuration
public class jdbcConfig {
    @Bean
    public DataSource createDataSource(){
        try {
            ComboPooledDataSource ds=new ComboPooledDataSource();
            ds.setDriverClass ("com.mysql.jdbc.Driver");
            ds.setJdbcUrl ("jdbc:mysql://127.0.0.1:3306/test1?serverTimezone=UTC&amp;useUnicode=true&amp;characterEncoding=UTF-8");
            ds.setUser ("root");
            ds.setPassword ("");
            return ds;
        } catch (PropertyVetoException e) {
            throw new RuntimeException (e);
        }
    }

    @Bean
    public QueryRunner createQueryRunner(DataSource ds){
        return new QueryRunner (ds);
    }
}

4)Import注解

在一个配置类中,导入另一个配置类,一般是父配置类v导入子配置类。value值为目标配置类的字节码文件

package config;

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


@Configuration
@ComponentScan("com.rootpackage")
@Import (jdbcConfig.class)//这里将子配置文件导入
public class springConfig {

}
ApplicationContext ac=new AnnotationConfigApplicationContext (springConfig.class);//创建容器时只需将父配置文件的字节码文件导入即可

5)Scope注解

value值标记实例是单例的还是多例的

6)PropertySource注解

将xxx.properties文件读取到spring的环境变量中,在变量上用@Value("${变量名}")可取到变量值

#duid.properties
# 注意:用户这里的变量是user,不可用username,username默认是admin无法使用
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/test1?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
user=root
password=
package config;

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


@Configuration
@ComponentScan("com.rootpackage")
@Import (jdbcConfig.class)
@PropertySource("classpath:druid.properties")//将properties文件读取到spring的环境中
public class springConfig {

}
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;

@Configuration
public class jdbcConfig {
    @Value ("${driverClassName}")//spEl表达式将变量读取到这里,并注入给变量
    private  String driverClassName;

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

    @Value ("${user}")
    private  String user;

    @Value ("${password}")
    private  String password;
    @Bean
    public DataSource createDataSource(){
        try {
            ComboPooledDataSource ds=new ComboPooledDataSource();
            ds.setDriverClass (driverClassName);
            ds.setJdbcUrl (url);
            ds.setUser (user);
            ds.setPassword (password);
            return ds;
        } catch (PropertyVetoException e) {
            throw new RuntimeException (e);
        }
    }

    @Bean
    public QueryRunner createQueryRunner(DataSource ds){
        return new QueryRunner (ds);
    }
}

7)Qualifier注解的另一种用法

package config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;

@Configuration
public class jdbcConfig {
    @Value ("${driverClassName}")
    private  String driverClassName;

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

    @Value ("${user}")
    private  String user;

    @Value ("${password}")
    private  String password;
    
    @Bean("ds1")
    public DataSource createDataSource(){
        try {
            ComboPooledDataSource ds=new ComboPooledDataSource();
            ds.setDriverClass (driverClassName);
            ds.setJdbcUrl (url);
            ds.setUser (user);
            ds.setPassword (password);
            return ds;
        } catch (PropertyVetoException e) {
            throw new RuntimeException (e);
        }
    }

    @Bean("ds2")
    public DataSource createDataSource1(){
        try {
            ComboPooledDataSource ds=new ComboPooledDataSource();
            ds.setDriverClass (driverClassName);
            ds.setJdbcUrl (url);
            ds.setUser (user);
            ds.setPassword (password);
            return ds;
        } catch (PropertyVetoException e) {
            throw new RuntimeException (e);
        }
    }

    //这里有两个datasource分别是ds1和ds2,默认情况下会无法注入而报错
    @Bean
    public QueryRunner createQueryRunner(@Qualifier("ds1")  DataSource ds){
        //此处的@Qualifier指定将ds1注入,就不会报错了
        return new QueryRunner (ds);
    }
}


Spring整合Junit

默认情况,测试时需要创建容器,获取容器中要测试的对象。为了方便,我们想在测试时,也想让程序自动创建容器且自动注入对象,需要使用Spring的整合Junit的依赖

1)pom.xml中导入依赖

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

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

注意两个依赖的版本,这里版本不对会报错

2)测试类上使用注解创建容器和自动注入


import com.rootpackage.doMain.Student;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import com.rootpackage.services.StudentServiceImpl;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;;

import java.util.List;

@RunWith (SpringJUnit4ClassRunner.class)//这个注解表示这个测试类是整合spring的
//@ContextConfiguration(classes=springConfig.class)
@ContextConfiguration(locations = "classpath:beans.xml")//创建容器,将配置文件导入,支持两种配置文件
public class test01 {
    @Autowired
    private StudentServiceImpl s=null;


    @Test
    public void findal(){
        List<Student> list=s.findAll ();
        for (Student i:
                list) {
            System.out.println (i);
        }
    }

    @Test
    public void insertone(){
        Student student=new Student ();
        student.setMale ("男");
        student.setName ("sylvester");
        student.setMath (85);
        student.setEnglish (90);
        s.insertOne (student);
    }

    @Test
    public void deleteone(){
        s.deleteOne (13);
    }

    @Test
    public void updateone(){
        Student student=new Student ();
        student.setId (15);
        student.setMale ("男");
        student.setName ("sylvester1");
        student.setMath (85);
        student.setEnglish (90);
        s.updateOne (student);
    }

    @Test
    public void findone(){
        Student student=s.findOne (15);
        System.out.println (student);
    }
}


银行转账案例

分析:转账过程中涉及事务操作,业务层包含持久层的多个操作,而者多个操作默认情况是多个事务,转账过程执行中报错易导致总数据量发生变化。为解决这个问题,我们使用Threadlocal将数据库的Connection存放进去,在业务层运行时,直接通过业务层的Threadlocal获取出Connection,开启事务进行一些列操作。

1目录结构

-main
	-java
		-com
            -rootpackage
                -dao
                    --accountDao
                    --accountDaoImpl
                -doMain
                    --Account
                -service
                    --AccountService
                    --AccountServiceImpl
                -utils
                    --ConnectionUtils
                    --TransactionManager
		-config
			--jdbcConfig
			--SpringConfig
	-resources
		--druid.properties
-test
	-java
		--test1

2文件代码

package com.rootpackage.dao;

import com.rootpackage.doMain.Account;

import java.util.List;

public interface accountDao {
    List<Account> findAll();
    void addOme(Account account);
    void deleteOne(int id);
    void updateOne(Account account);
    Account findOne(int id);
}

package com.rootpackage.dao;

import com.rootpackage.doMain.Account;
import com.rootpackage.utils.ConnectionUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.sql.SQLException;
import java.util.List;
@Component
public class accountDaoImpl implements accountDao {
    @Autowired
    private QueryRunner runner;
    @Autowired
    private ConnectionUtils connectionUtils;
    public List<Account> findAll() {
        try {
            return runner.query (connectionUtils.getThreadConnection (),"select * from account",new BeanListHandler<Account> (Account.class));
        } catch (SQLException e) {
            throw new RuntimeException (e);
        }
    }

    public void addOme(Account account) {
        try {
            runner.update (connectionUtils.getThreadConnection (),"insert into account (name,money) values (?,?)",account.getName (),account.getMoney ());
        } catch (SQLException e) {
            throw new RuntimeException (e);
        }
    }

    public void deleteOne(int id) {
        try {
            runner.update (connectionUtils.getThreadConnection (),"delete from account where id=?",id);
        } catch (SQLException e) {
            throw new RuntimeException (e);
        }
    }

    public void updateOne(Account account) {
        try {
            runner.update (connectionUtils.getThreadConnection (),"update account set name=?,money=? where id=?",account.getName (),account.getMoney (),account.getId ());
        } catch (SQLException e) {
            throw new RuntimeException (e);
        }
    }

    public Account findOne(int id) {
        try {
            return runner.query (connectionUtils.getThreadConnection (),"select * from account where id=?",new BeanHandler<Account> (Account.class),id);
        } catch (SQLException e) {
            throw new RuntimeException (e);
        }
    }
}

package com.rootpackage.doMain;

public class Account {
    private int id;
    private String name;
    private int money;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

package com.rootpackage.service;

import com.rootpackage.doMain.Account;

import java.util.List;

public interface AccountService {
    List<Account> findAll();
    void addOme(Account account);
    void deleteOne(int id);
    void updateOne(Account account);
    Account findOne(int id);
    void transfer(int id1,int id2,int money);
}

package com.rootpackage.service;

import com.rootpackage.doMain.Account;
import com.rootpackage.utils.TransactionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import com.rootpackage.dao.accountDaoImpl;

@Component
public class AccountServiceImpl implements AccountService {
    @Autowired
    private accountDaoImpl dao;
    @Autowired
    private TransactionManager manager;

    public List<Account> findAll() {
        try {
            manager.beginTransaction ();
            List<Account> list=dao.findAll ();
            manager.commit ();
            return list;
        } catch (Exception e) {
            manager.rollback ();
            throw new RuntimeException (e);
        } finally {
            manager.release ();
        }
    }

    public void addOme(Account account) {
        try {
            manager.beginTransaction ();
            dao.addOme (account);
            manager.commit ();
        } catch (Exception e) {
            manager.rollback ();
            throw new RuntimeException (e);
        } finally {
            manager.release ();
        }
    }

    public void deleteOne(int id) {
        try {
            manager.beginTransaction ();
            dao.deleteOne (id);
            manager.commit ();
        } catch (Exception e) {
            manager.rollback ();
            throw new RuntimeException (e);
        } finally {
            manager.release ();
        }
    }

    public void updateOne(Account account) {
        try {
            manager.beginTransaction ();
            dao.updateOne (account);
            manager.commit ();
        } catch (Exception e) {
            manager.rollback ();
            throw new RuntimeException (e);
        } finally {
            manager.release ();
        }
    }

    public Account findOne(int id) {
        try {
            manager.beginTransaction ();
            Account a=dao.findOne (id);
            manager.commit ();
            return a;
        } catch (Exception e) {
            manager.rollback ();
            throw new RuntimeException (e);
        } finally {
            manager.release ();
        }
    }

    public void transfer(int id1, int id2, int money) {
        try {
            manager.beginTransaction ();
            Account a1=dao.findOne (id1);
            Account a2=dao.findOne (id2);
            a1.setMoney (a1.getMoney ()-money);
            a2.setMoney (a2.getMoney ()+money);
            dao.updateOne (a1);
            int a=10/0;//这里会报错,但是会进行回滚,数据总量不会发生改变
            dao.updateOne (a2);
            manager.commit ();
        } catch (Exception e) {
            manager.rollback ();
            throw new RuntimeException (e);
        } finally {
            manager.release ();
        }
    }
}

package com.rootpackage.utils;

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

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

@Component
public class ConnectionUtils {
    private ThreadLocal<Connection> t1=new ThreadLocal<Connection> ();
    //一个线程内部的存储类,可以在指定线程内存储数据,数据存储以后,只有指定线程可以得到存储数据
    @Autowired
    private DataSource dataSource;

    public Connection getThreadConnection(){
        try {
            Connection con=t1.get ();
            if(con==null){
                con=dataSource.getConnection ();
                t1.set (con);
            }
            return con;
        } catch (SQLException e) {
            throw new RuntimeException (e);
        }
    }
    public void removeConnection(){
        t1.remove ();
    }
}

package com.rootpackage.utils;

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

import java.sql.SQLException;

@Component
public class TransactionManager {
    @Autowired
    private ConnectionUtils connectionUtils;

    public void beginTransaction(){
        try {
            connectionUtils.getThreadConnection ().setAutoCommit (false);
        } catch (SQLException e) {
            e.printStackTrace ( );
        }
    }
    public void commit(){
        try {
            connectionUtils.getThreadConnection ().commit ();
        } catch (SQLException e) {
            e.printStackTrace ( );
        }
    }
    public void rollback(){
        try {
            connectionUtils.getThreadConnection ().rollback ();
        } catch (SQLException e) {
            e.printStackTrace ( );
        }
    }
    public void release(){
        connectionUtils.removeConnection ();
    }
}

package config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;

@Configuration
public class jdbcConfig {
    @Value ("${driverClassName}")
    private  String driverClassName;

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

    @Value ("${user}")
    private  String user;

    @Value ("${password}")
    private  String password;

    @Bean
    public DataSource createdatasource(){
        try {
            ComboPooledDataSource ds=new ComboPooledDataSource();
            ds.setDriverClass (driverClassName);
            ds.setJdbcUrl (url);
            ds.setUser (user);
            ds.setPassword (password);
            return ds;
        } catch (PropertyVetoException e) {
            throw new RuntimeException (e);
        }
    }

    @Bean
    public QueryRunner createqueryrunner(DataSource ds){
        return new QueryRunner (ds);
    }
}

package config;

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

@Configuration
@ComponentScan("com.rootpackage")
@PropertySource("classpath:druid.properties")
@Import (jdbcConfig.class)
public class SpringConfig {

}

#duid.properties
# 注意:用户这里的变量是user,不可用username,username默认是admin无法使用
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/test2?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
user=root
password=
import com.rootpackage.doMain.Account;
import com.rootpackage.service.AccountServiceImpl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import config.SpringConfig;

import java.util.List;

@RunWith (SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class test1 {
    @Autowired
    private AccountServiceImpl service;
    @Test
    public void findall(){
        List<Account> list=service.findAll ();
        for (Account a:
             list) {
            System.out.println (a);
        }
    }
    @Test
    public void transfer(){

        service.transfer (1,2,500);
    }
}


代理

1jdk中的代理类

java在JDK1.5之后提供了一个"java.lang.reflect.Proxy"类,通过"Proxy"类提供的一个newProxyInstance方法用来创建一个对象的代理对象

//部分代码
final computermaker m=new computermaker ();//该被代理对象必须实现一个接口,并且final关键字修饰
        saler n=(saler) Proxy.newProxyInstance (m.getClass ( ).getClassLoader ( ), m.getClass ().getInterfaces (), new InvocationHandler ( ) {
            /*
            ClassLoader 类加载器,让代理对象和被代理对象使用相同的类加载器
            Class[] 字节码数组,让代理对象和被代理对象有相同的方法
            InvocationHandler 需要创建一个该接口的匿名内部类,并重写invoke方法以增强
             */
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return method.invoke (m,args);//注意:第一个参数是被代理对象,最后一个参数是该方法传过来的参数
            }
        });
        n.sale ();

2第三方代理类

由于jdk提供的代理要求被代理对象必须实现接口,对于没有实现接口的被代理对象可使用第三方代理类

1)pom.xml导入依赖

		<dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>

2)部分代码

final computermaker m=new computermaker ();
        computermaker n=(computermaker)Enhancer.create (m.getClass ( ), new MethodInterceptor ( ) {
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                return method.invoke (m,objects);
            }
        });
        n.sale ();

3转账案例改用代理

1)AccountServiceImpl修改简化

package com.rootpackage.service;

import com.rootpackage.doMain.Account;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import com.rootpackage.dao.accountDaoImpl;

@Component("accountservice")
public class AccountServiceImpl implements AccountService {
    @Autowired
    private accountDaoImpl dao;


    public List<Account> findAll() {
        List<Account> list=dao.findAll ();
        return list;
    }

    public void addOme(Account account) {
        dao.addOme (account);
    }

    public void deleteOne(int id) {
        dao.deleteOne (id);
    }

    public void updateOne(Account account) {
        dao.updateOne (account);
    }

    public Account findOne(int id) {
        Account a=dao.findOne (id);
        return a;
    }

    public void transfer(int id1, int id2, int money) {
        Account a1=dao.findOne (id1);
        Account a2=dao.findOne (id2);
        a1.setMoney (a1.getMoney ()-money);
        a2.setMoney (a2.getMoney ()+money);
        dao.updateOne (a1);
        int a=9/0;
        dao.updateOne (a2);
    }
}

2)新建代理工厂

package com.rootpackage.factory;

import com.rootpackage.service.AccountService;
import com.rootpackage.utils.TransactionManager;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Component
public class BeanFactory {
    @Autowired
    @Qualifier("accountservice")
    private AccountService accountService;
    @Autowired
    private TransactionManager manager;
    public AccountService getAccountService(){
        return (AccountService)Enhancer.create (accountService.getClass ( ), new MethodInterceptor ( ) {
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                Object result=null;
                try {
                    manager.beginTransaction ();
                    result=method.invoke (accountService,objects);
                    manager.commit ();
                    return result;
                } catch (Exception e) {
                    manager.rollback ();
                    throw new RuntimeException (e);
                } finally {
                    manager.release ();
                }
            }
        });
    }
}

3)测试类

import com.rootpackage.doMain.Account;
import com.rootpackage.factory.BeanFactory;
import com.rootpackage.service.AccountServiceImpl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import config.SpringConfig;

import java.util.List;

@RunWith (SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class test1 {
    @Autowired
    private BeanFactory factory;
    @Test
    public void findall(){
        List<Account> list=factory.getAccountService ().findAll ();//通过代理工厂获取AccountService对象
        for (Account a:
             list) {
            System.out.println (a);
        }
    }
    @Test
    public void transfer(){

        factory.getAccountService ().transfer (1,2,500);
    }

}


AOP面向切面编程

Aspect Oriented Programming,是spring框架中一个重要内容,是函数式编程的一种衍生范型。利用AOP可对业务逻辑各个部分进行隔离,从而使业务逻辑各个部分间耦合度降低。

特点:在程序运行期间,不改变源码对已有方法进行增强

优势:减少重复代码,提高开发效率,维护方便

1常用名词

名词 英文 解释
连接点 joinpoint 已经被增强的挂载点,如增强的方法
切入点 pointcut 所有可以被拦截的点(方法)
通知 advice 拦截到切入点后要做的事情
映入 introduction 运行期动态添加的方法或Field
目标对象 target 代理的目标对象
织入 weaving 增强应用到目标对象来创建新的代理对象的过程
代理 proxy 一个类被aop增强后的一个结果类
切面 aspect 切入点和通知的结合

2快速开始

1)pom.xml导入依赖

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

2)定义一个服务类

package com.rootpackage.services;

public class service1 {
    public void doservice(){
        System.out.println ("开始服务……");
    }
}

3)定义一个日志类

package com.rootpackage.mout;

public class log {
    public void dolog1(){
        System.out.println ("打印日志1");
    }
    public void dolog2(){
        System.out.println ("打印日志2");
    }
    public void dolog3(){
        System.out.println ("打印日志3");
    }
    public void dolog4(){
        System.out.println ("打印日志4");
    }
}

4)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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="service1" class="com.rootpackage.services.service1"></bean>
    <bean id="log" class="com.rootpackage.mout.log"></bean>
    <aop:config>
        <aop:aspect id="asp1" ref="log">
            <!--id是给这个切面的id,ref指向通知类(放入切入点的方法所属的类)-->
            <aop:before method="dolog1" pointcut="execution(* *..*.doservice(..))"></aop:before>
            <!--method是通知方法的方法名,pointcut切入点-->
            <aop:after-returning method="dolog2" pointcut="execution(* *..*.doservice(..))"></aop:after-returning>
            <aop:after-throwing method="dolog3" pointcut="execution(* *..*.doservice(..))"></aop:after-throwing>
            <aop:after  method="dolog4" pointcut="execution(* *..*.doservice(..))"></aop:after>
        </aop:aspect>
    </aop:config>
</beans>

5)测试类

import com.rootpackage.services.service1;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations ="classpath:beans.xml" )
public class test1 {
    @Autowired
    service1 sv1;

    @Test
   public void test1(){

       sv1.doservice ();
   }
}

3execution指定切点的格式

访问修饰符 返回值 包名 类名 .方法名(参数类型)
格式 通配符 说明
访问修饰符 *
返回值 *
包名 *,..
类名 *
方法名 *
参数类型 *,.. 直接写数据类型如int,java.lang.String,可有参数,也可无参数

全通配* *..*.*(..),但通常情况都不用全同配。切入到业务实现类的所有方法,会有一个问题就是通知内容会多执行一次,是由于构造方法导致的。

4四种通知类型

关键字 类型
before 前置
after-returning 后置
after-throwing 异常
after 最终

5配置共用切入点

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="service1" class="com.rootpackage.services.service1"></bean>
    <bean id="log" class="com.rootpackage.mout.log"></bean>
    <aop:config>
        <aop:pointcut id="s1" expression="execution(* * ..*.doservice(..))"></aop:pointcut>
        <aop:aspect id="asp1" ref="log">
            <aop:before method="dolog1" pointcut-ref="s1"></aop:before>
            <aop:after-returning method="dolog2" pointcut-ref="s1"></aop:after-returning>
            <aop:after-throwing method="dolog3" pointcut-ref="s1"></aop:after-throwing>
            <aop:after  method="dolog4" pointcut-ref="s1"></aop:after>
        </aop:aspect>
    </aop:config>
</beans>

6环绕通知

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="service1" class="com.rootpackage.services.service1"></bean>
    <bean id="log" class="com.rootpackage.mout.log"></bean>
    <aop:config>
        <aop:pointcut id="s1" expression="execution(* * ..*.doservice(..))"></aop:pointcut>
        <aop:aspect id="asp1" ref="log">
            <aop:around method="doarround" pointcut-ref="s1"></aop:around>
        </aop:aspect>
    </aop:config>
</beans>

配置环绕通知后,只有通知方法执行,切入点原方法未执行。此时需要在通知方法中传入ProceedingJoinPoint的实现类(定义该接口的参数,spring自动传入实现类),再通过该实现类调用切入点方法

package com.rootpackage.mout;

import org.aspectj.lang.ProceedingJoinPoint;

public class log {
    public void doarround(ProceedingJoinPoint pjp){
        try {
            System.out.println ("打印日志1");
            Object[] args=pjp.getArgs ();//获取切入点参数
            pjp.proceed (args);//调用切入点方法
            System.out.println ("打印日志2");
        } catch (Throwable throwable) {
            throwable.printStackTrace ( );
            System.out.println ("打印日志3");
        } finally {
            System.out.println ("打印日志4");
        }
    }
}

7注解

1)Aspect注解

表示该类是一个切面内

2)Before注解

表示该方法是一个前置通知

3)After注解

表示该方法是一个最终通知

4)AfterReturning注解

表示该方法是一个后置通知

5)AfterThrowing注解

表示该方法是一个异常通知

6)Arround注解

表示该方法是一个环绕通知

7)Point注解

定义一个切点,定义在一个方法上,参数是“execution(...)”,引用切面是需要调用该方法

在定义切面、通知前需要在配置文件中配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="service1" class="com.rootpackage.services.service1"></bean>
    <bean id="log" class="com.rootpackage.mout.log"></bean>
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy><!--需要配置这一句-->
</beans>
package com.rootpackage.mout;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;


@Aspect//标识该类是一个切面类
public class log {

    @Pointcut("execution(* *..*.doservice(..))")//定义切点
    public void pf(){}

    @Before ("pf()")//定义前置通知
    public void dolog1(){
        System.out.println ("打印日志1");
    }
    @AfterReturning("pf()")
    public void dolog2(){
        System.out.println ("打印日志2");
    }
    @AfterThrowing("pf()")
    public void dolog3(){
        System.out.println ("打印日志3");
    }
    @After ("pf()")
    public void dolog4(){
        System.out.println ("打印日志4");
    }
}

执行后发现最终通知在后置通知之前执行,不合理。所以建议使用环绕通知

package com.rootpackage.mout;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;


@Aspect//标识该类是一个切面类
public class log {

    @Pointcut("execution(* *..*.doservice(..))")//定义切点
    public void pf(){}
    
	@Around ("pf()")
    public void doarround(ProceedingJoinPoint pjp){
        try {
            System.out.println ("打印日志1");
            Object[] args=pjp.getArgs ();
            pjp.proceed (args);
            System.out.println ("打印日志2");
        } catch (Throwable throwable) {
            throwable.printStackTrace ( );
            System.out.println ("打印日志3");
        } finally {
            System.out.println ("打印日志4");
        }
    }
}

9)不使用xml配置

此时应该在配置类上加一行注解@EnableAspectJAutoProxy

8转账案例使用切面新增事务

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

    <context:component-scan base-package="org.zhanghuan"></context:component-scan>
    <bean id="ds" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/test2?serverTimezone=UTC&amp;useUnicode=true&amp;characterEncoding=UTF-8"></property>
        <property name="user" value="root"></property>
        <property name="password" value=""></property>
    </bean>
    <bean class="org.apache.commons.dbutils.QueryRunner">
        <constructor-arg name="ds" ref="ds"></constructor-arg>
    </bean>
    <aop:config><!--将事务通过切面织入-->
        <aop:pointcut id="p1" expression="execution(* org.zhanghuan.service.AccountServiceImpl.*(..))"></aop:pointcut>
        <aop:aspect id="isp1" ref="transaction">
            <aop:before method="beginTransaction" pointcut-ref="p1"></aop:before>
            <aop:after method="release" pointcut-ref="p1"></aop:after>
            <aop:after-returning method="commit" pointcut-ref="p1"></aop:after-returning>
            <aop:after-throwing method="rollback" pointcut-ref="p1"></aop:after-throwing>
        </aop:aspect>
    </aop:config>
    </beans>

9DataSourceTransactionManager的使用

Spring的事务处理中,通用的事务处理流程是由抽象事务管理器AbstractPlatformTransactionManager来提供的,而具体的底层事务处理实现,由PlatformTransactionManager的具体实现类来实现

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: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/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">

    <context:component-scan base-package="org.zhanghuan"></context:component-scan>
    <bean id="ds" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/test2?serverTimezone=UTC&amp;useUnicode=true&amp;characterEncoding=UTF-8"></property>
        <property name="user" value="root"></property>
        <property name="password" value=""></property>
    </bean>
    <bean class="org.apache.commons.dbutils.QueryRunner">
        <constructor-arg name="ds" ref="ds"></constructor-arg>
    </bean>

    <!--导入事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!--这个包在spring-jdbc中,需在maven中导入-->
        <property name="dataSource" ref="ds"></property>
    </bean>

    <!--配置事务通知-->
    <tx:advice id="manager" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED" read-only="false"></tx:method>
            <tx:method name="*find*" propagation="SUPPORTS" read-only="true"></tx:method><!--表示包含find关键字的方法,只读,不一定包含事务-->
        </tx:attributes>
    </tx:advice>

    <!--配置aop,将事务通知织入-->
    <aop:config>
        <aop:pointcut id="p1" expression="execution(* org.zhanghuan.service.AccountServiceImpl.*(..))"></aop:pointcut>
        <aop:advisor advice-ref="manager" pointcut-ref="p1"></aop:advisor>
    </aop:config>
    </beans>

事务通知里方法的属性

属性名 含义
isolation 事务隔离级别
propagation 指定事务传播形式,默认REQUIRED,表示必有事务。对于查询的方法,使用SUPPORTS
read-only 指定事务是否只读,默认false,查询方法设置未true
timeout 指定事务超时时间,默认未-1,表示永不超时。如果设置值,以秒未单位
rollback-for 指定一个异常,该异常发生,则回滚;其他异常发生,不回滚。无默认值,未设置表示出现任何异常都回滚
no-rollback-for 指定一个异常,该异常发生,不回滚;其他异常发生,回滚。无默认值,未设置表示出现任何异常都回滚

2)注解配置方式

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns: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/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">

    <context:component-scan base-package="org.zhanghuan"></context:component-scan>
    <bean id="ds" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/test2?serverTimezone=UTC&amp;useUnicode=true&amp;characterEncoding=UTF-8"></property>
        <property name="user" value="root"></property>
        <property name="password" value=""></property>
    </bean>
    <bean class="org.apache.commons.dbutils.QueryRunner">
        <constructor-arg name="ds" ref="ds"></constructor-arg>
    </bean>

    <!--导入事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!--这个包在spring-jdbc中,需在maven中导入-->
        <property name="dataSource" ref="ds"></property>
    </bean>

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

    <!--在需要开启事务的地方表上注解@Transactional-->
    </beans>

在配置文件中完成以上配置后,在需要开启事务的地方表上注解@Transactional

3)无xml方式

//配置文件
package org.zhanghuan.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

@Configuration
@Import (jdbcConfig.class)
@ComponentScan("org.zhanghuan")
@EnableTransactionManagement//相当于xml中的tx:annotation-driven标签+@Transactional注解
public class springConfig {
    @Bean//导入事务管理器
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource ds){
        return new DataSourceTransactionManager(ds);
    }
}

找到事务实现类,并开启事务


JDBCTemplate

1pom.xml导入依赖

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

2快速使用

//部分代码 		
 		//创建数据源
       DriverManagerDataSource ds=new DriverManagerDataSource ();
       ds.setDriverClass ("com.mysql.jdbc.Driver");
       ds.setJdbcUrl ("jdbc:mysql://127.0.0.1:3306/test2?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8");
       ds.setUser ("root");
       ds.setPassword ("");

       JdbcTemplate template=new JdbcTemplate (ds);
       List<Map<String,Object>> list=template.queryForList ("select * from account");
       for (Map<String,Object> m:
            list) {
           System.out.println ("id:"+m.get ("id"));
       }

3query方法

query(String sql,Objectp[] args,RowMapper<T> rowmapper);//所有版本可用

query(String sql,RowMapper<T> rowmapper,Object.. args);//jdk1.5之后可用

标签:23,Spring,void,springframework,class,2020,org,import,public
From: https://www.cnblogs.com/sylvesterzhang/p/18089852

相关文章

  • 2020-1-1-GIT使用经验汇总
    Git安装、创建版本库、同步操作、分支管理、查看版本记录、远程仓库相关操作安装sudoapt-getinstallgit设置用户名和邮箱gitconfig--globaluser.name"yourname"gitconfig--globaluser.email"[email protected]"创建版本库1.创建目录mkdirlearniggitcdlearn......
  • 2020-1-3-ekyll安装使用
    jekyll是一个博客工具,将markdown文件生成静态网页,具有较好的迁移性。安装依赖包RubyRubyGemsNodeJsPython安装完成后重启电脑配置gem镜像$gemsources--addhttps://gems.ruby-china.com/--removehttps://rubygems.org/$gemsources-l安装jeckyll-pagination$g......
  • 2020-1-9-js新特性第二部分
    实现map函数、嵌套函数和闭包、arguments对象、函数参数、关系操作符、遍历数组foreach方法、map对象与object对象的区别、promise对象、生成器实现Map函数传入处理函数和数组,返回值为将数组内的数按照函数规则处理后新生成的数组window.onload=function(){functio......
  • 2020-1-6-js新特性第一部分
    var、let、const的区别,对象被定义为常量不受保护,自执行函数注意事项,箭头函数特点,对象扩展运算和对象解构运算,label语句,for...in...和for...of...的区别var、let、const的区别varletconst作用域函数花括号内全局是否可重复声明可以不可以不可以声明后是......
  • 搭建麒麟桌面操作系统V10 SP1 2303的内网全量仓库源
    来源:公众号鹏大圣运维作者:鹏大圣免责声明本文所有内容,只在测试环境中进行,如果您要使用文章中的内容对您的环境进行操作,请您一定知悉:所有的操作都会带来一定的风险,可能会导致系统崩溃等多种问题,切勿盲目操作,本公众号为您提供一种操作的思路,不对您的任何操作行为负责,请您知......
  • Spring中getBean的生命周期和整个链路原理
    publicabstractclassAbstractBeanFactoryextendsFactoryBeanRegistrySupportimplementsConfigurableBeanFactory{publicObjectgetBean(Stringname)throwsBeansException{returndoGetBean(name,null,null,false);}protected<T&......
  • 一、SpringBoot基础搭建
    本教程主要给初学SpringBoot的开发者,通过idea搭建单体服务提供手把手教学例程,主要目的在于理解环境的搭建,以及maven模块之间的整合与调用源码:jun/learn-springboot以商城项目为搭建例子,首先计划建1个父模块,3个子模块:父模块(你可以理解为共用模块,约定共用参数以及公用jar等)s......
  • SpringBoot3.x与SpringDoc OpenApi之Swagger接口排序
    直接使用Swagger之后,发现所有的Controller接口菜单都是无序的先看一下效果 就是利用了一下SpringDoc提供的接口做了一下自定义排序1.在Controller上加上注解@Tag(name="MenuController",description="1-菜单管理")这里需要注意description属性,在下面的代码里......
  • Dubbo23_Dubbo相关配置说明6
    一、包扫描<dubbo:annotationpackage="com.itheima.service"/>服务提供者和服务消费者都需要配置,表示包扫描,作用是扫描指定包(包括子包)下的类。如果不使用包扫描,也可以通过如下配置的方式来发布服务-不推荐:<beanid="helloService"class="com.itheima.service.impl......
  • 基于springboot+vue的乡村民宿管理系统
    一、系统架构        前端:vue|element-ui        后端:springboot|mybatis-plus        环境:jdk1.8+|mysql|maven|nodejs二、代码及数据库        三、功能介绍   01.登录页  02.注册 03.管理员-首页 ......