Spring学习

Posted WBlog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring学习相关的知识,希望对你有一定的参考价值。

一、Spring介绍

Spring负责管理项目中的所有对象。Spring是一站式框架,仅仅使用Spring足以完成Web项目。 
技术分享图片

 

二、Spring项目搭建以及测试
环境为IDEA,Spring项目创建:

 

创建一个对象:

public class User {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

配置文件(建议放到src下面):

<?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">
    <!--将user对象交给Spring容器-->
    <bean id="user" class="domain.User">
        <property name="name" value="helloworld"></property>
    </bean>
</beans>

测试代码:

 

public class Main {
    public static void main(String[] args){
        //创建容器对象
        //ApplicationContext对象在加载 spring-config.xml(容器启动)时候就会创建
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        //向容器要user对象
        User user = (User) context.getBean("user");
        System.out.println(user.getName());
    }
}

运行结果:helloworld

 

 

三、IOC和DI
IOC:Inverse Of Control反转控制。即将我们创建对象的方式反转,以前对象的创建和依赖关系是我们自己维护。使用Spring之后,对象的创建以及依赖关系可以由Spring完成创建以及注入。
DI:Dependency Injection依赖注入,实现IOC思想需要DI做支持,注入方式:set方式注入、构造方式注入、字段注入。注入类型:值类型注入、引用类型注入。

四、三种创建对象方式

4.1、空参构造方法创建

public class User {
    public User() {
    }
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = 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">
    <!--创建方式1:空参构造创建-->
    <bean name="user" class="domain.User">
        <property name="name" value="naruto"></property>
    </bean>
</beans>

4.2、静态工厂方法创建

public class UserFactory {
    public static User createUser(){
        System.out.println("静态工厂创建User");
        return new User();
    }
}
<?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">
    <!-- 创建方式2:静态工厂创建
          调用UserFactory的createUser方法创建名为user2的对象.放入容器
     -->
    <bean  name="user2"
           class="domain.UserFactory"
           factory-method="createUser" >
    </bean>
</beans>

4.3、实例工厂方法创建

public class UserFactory {
    public  User createUser2(){
        System.out.println("实例工厂创建User");
        return new User();
    }
}
<?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">
    <!-- 创建方式3:实例工厂创建
         调用UserFactory对象的createUser2方法创建名为user3的对象.放入容器
     -->
    <bean  name="user3"
           factory-bean="userFactory"
           factory-method="createUser2" >
    </bean>
    <bean  name="userFactory"
           class="domain.UserFactory"   >
    </bean>
</beans>

五、Scpoe属性

Scpoe即Bean的作用范围:
singleton :默认值,单例的。
prototype :多例的
request :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中。
session :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中。(了解即可)
globalSession :WEB 项目中,应用在 Porlet 环境.如果没有 Porlet 环境那么 globalSession 相当于 session。(了解即可)

六、模块化配置

在一个配置文件中包含另一个配置文件:

 

<import resource="applicationContext2.xml"></import>

 

七、Spring属性注入

7.1、set方法注入

User对象:

 

public class User {
    public User() {
    }
    private String name;
    private Car car;
    public Car getCar() {
        return car;
    }
    public void setCar(Car car) {
        this.car = car;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "User{" +
                "name=‘" + name + ‘‘‘ +
                ", car=" + car +
                ‘}‘;
    }
}

 

Car对象:

public class Car {
    private String color;
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
    @Override
    public String toString() {
        return "Car{" +
                "color=‘" + color + ‘‘‘ +
                ‘}‘;
    }
}

注入容器:

<?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.spring
       framework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--set方式注入-->
    <bean name="user6" class="domain.User">
        <!--为User对象中名为name的属性注入naruto-->
        <property name="name" value="naruto"></property>
        <property name="car" ref="car"></property>
    </bean>
    <!--将car对象配置到容器中-->
    <bean name="car" class="domain.Car">
        <!--为car对象中名为color的属性注入yellow-->
        <property name="color" value="yellow"></property>
    </bean>
</beans>

运行测试:

public class Main {
    public static void main(String[] args){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        User user = (User) context.getBean("user6");
        System.out.println(user.toString());
    }
}

运行结果:User{name=’naruto’, car=Car{color=’yellow’}}

7.2、构造函数注入

User对象:

 

public class User {
    public User() {
    }
    private String name;
    private Car car;

    public User(Car car, String name) {
        this.car = car;
        this.name = name;
    }

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "name=‘" + name + ‘‘‘ +
                ", car=" + car +
                ‘}‘;
    }
}!

 

配置:

<?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">
    <!--将car对象配置到容器中-->
    <bean name="car" class="domain.Car">
        <!--为car对象中名为color的属性注入yellow-->
        <property name="color" value="yellow"></property>
    </bean>
    <!--构造方法注入-->
    <bean name="user66" class="domain.User">
        <!--为User对象中名为name的属性注入naruto-->
        <constructor-arg name="name" value="long" index="1"></constructor-arg>
        <constructor-arg name="car" ref="car"></constructor-arg>
    </bean>
</beans>

运行测试:

public class Main {
    public static void main(String[] args){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        User user = (User) context.getBean("user66");
        System.out.println(user.toString());
    }
}

7.3、复杂类型注入

创建一个复杂对象:

 

public class CollectionBean {
    private Object[] arr;//数组类型注入
    private List list;//list/set 类型注入
    private Map map;//map类型注入
    private Properties prop;//properties类型注入

    public Object[] getArr() {
        return arr;
    }
    public void setArr(Object[] arr) {
        this.arr = arr;
    }
    public List getList() {
        return list;
    }
    public void setList(List list) {
        this.list = list;
    }
    public Map getMap() {
        return map;
    }
    public void setMap(Map map) {
        this.map = map;
    }
    public Properties getProp() {
        return prop;
    }
    public void setProp(Properties prop) {
        this.prop = prop;
    }
    @Override
    public String toString() {
        return "CollectionBean [arr=" + Arrays.toString(arr) + ", list=" + list + ", map=" + map + ", prop=" + prop
                + "]";
    }
}

 

配置:

<!-- ============================================================= -->
   <!-- 复杂类型注入 -->
   <bean name="cb" class="domain.CollectionBean" >
       <!-- 如果数组中只准备注入一个值(对象),直接使用value|ref即可
       <property name="arr" value="tom" ></property>
       -->
       <!-- array注入,多个元素注入 -->
       <property name="arr">
           <array>
               <value>tom</value>
               <value>jerry</value>
               <ref bean="user6" />
           </array>
       </property>
       <!-- 如果List中只准备注入一个值(对象),直接使用value|ref即可
       <property name="list" value="jack" ></property>-->
       <property name="list"  >
           <list>
               <value>jack</value>
               <value>rose</value>
               <ref bean="user3" />
           </list>
       </property>
       <!-- map类型注入 -->
       <property name="map"  >
           <map>
               <entry key="url" value="jdbc:mysql:///crm" ></entry>
               <entry key="user" value-ref="user6"  ></entry>
               <entry key-ref="user3" value-ref="user2"  ></entry>
           </map>
       </property>
       <!-- prperties 类型注入 -->
       <property name="prop"  >
           <props>
               <prop key="driverClass">com.jdbc.mysql.Driver</prop>
               <prop key="userName">root</prop>
               <prop key="password">1234</prop>
           </props>
       </property>
   </bean>

八、Spring整合Web项目配置

配置监听器:

 

<!-监听器:服务器启动,Spring对象创建,服务器销毁,Spring对象销毁。-->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listenerclass>
</listener>
<!--指定加载Spring配置文件的位置。-->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>

 

Spring将容器放入ServletContext中去了,即可以从Application域中获取Spring对象。

九、使用注解配置Spring

配置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>

将car对象注入到Spring中:

@Component("car2")
public class Car {
    @Value("yellow")
    private String color;

    public void setColor(String color) {
        this.color = color;
    }
    @Override
    public String toString() {
        return "Car{" +
                "color=‘" + color + ‘‘‘ +
                ‘}‘;
    }
}

将user对象注入到Spring中:

//对象名为user,将其放入Spring容器中
@Component("user")
//@Service("user")       //service层
//@Controller("user")    //web层
//@Repository("user")    //dao层
//@Scope(scopeName = "protoType")  //指定对象作用范围:多例
public class User {
    @Value("long")  //通过反射的Field赋值,破坏了封装性
    private String name;
    //@Autowired      //自动装配
    //自动装配问题:如果匹配多个类型一致的对象,将无法选择具体注入哪一个对象
    //@Qualifier("car2")  使用Qualifier注解告诉Spring容器自动装配哪个名称的对象
    //使用Resource注解手动注入,指定注入哪个名称的对象(推荐)
    @Resource(name="car2")
    private Car car;
    @PostConstruct   //在对象被创建后调用
    public void init(){
        System.out.println("我是初始化方法");
    }
    @PreDestroy      //在对象被销毁之前调用
    public void destroy(){
        System.out.println("我是销毁方法");
    }

    public Car getCar() {
        return car;
    }
    public void setCar(Car car) {
        this.car = car;
    }

    public String getName() {
        return name;
    }
    //@Value("long")  //通过set方法赋值(推荐)
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "User{" +
                "name=‘" + name + ‘‘‘ +
                ", car=" + car +
                ‘}‘;
    }
}

测试:

public class Main {
    public static void main(String[] args){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        User bean = (User) context.getBean("user");
        System.out.println(bean.toString());
    }
}

运行结果:
我是初始化方法
User{name=’long’, car=Car{color=’yellow’}}

十、Spring中的AOP
Spring能够为容器中管理的对象生成动态代理对象。
Spring实现Aop的原理:Spring封装了动态代理和cglib代理
动态代理局限性:被代理对象必须要有接口,才能产生代理对象。
cglib代理:第三方代理技术,可以对任何类生成代理。代理的原理是对目标对象进行继承代理。如果目标对象被final修饰,那么该类无法被cglib代理。
使用动态代理:
UserService:

public interface UserService {
    void save();
    void delete();
    void update();
    void find();
}

UserServiceImpl:

public class UserServiceImpl implements UserService {
    @Override
    public void save() {
        System.out.println("保存用户!");
        //int i = 1/0;
    }
    @Override
    public void delete() {
        System.out.println("删除用户!");
    }
    @Override
    public void update() {
        System.out.println("更新用户!");
    }
    @Override
    public void find() {
        System.out.println("查找用户!");
    }
}

生成代理:

public class UserServiceProxyFactory implements InvocationHandler {
    public UserServiceProxyFactory(UserService us) {
        super();
        this.us = us;
    }
    private UserService us;
    public UserService getUserServiceProxy(){
        //生成动态代理
        UserService usProxy = (UserService) Proxy.newProxyInstance(UserServiceProxyFactory.class.getClassLoader(),
                UserServiceImpl.class.getInterfaces(),  //被代理对象实现的接口
                this);
        //返回
        return usProxy;
    }
    @Override
    public Object invoke(Object arg0, Method method, Object[] arg2) throws Throwable {
        System.out.println("打开事务!");
        Object invoke = method.invoke(us, arg2);
        System.out.println("提交事务!");
        return invoke;
    }
}

测试:

public class Demo {
    @Test
    //动态代理
    public void fun1(){
        UserService us = new UserServiceImpl();
        //传入代理对象
        UserServiceProxyFactory factory = new UserServiceProxyFactory(us);
        UserService usProxy = factory.getUserServiceProxy();
        usProxy.save();
        //代理对象与被代理对象实现了相同的接口
        //代理对象 与 被代理对象没有继承关系
        System.out.println(usProxy instanceof UserServiceImpl );//false
    }
}

运行结果: 
打开事务! 
保存用户! 
提交事务! 
false 

2、动态代理

什么是代理(中介)
目标对象/被代理对象 —— 房主:真正的租房的方法
代理对象 ——- 黑中介:有租房子的方法(调用房主的租房的方法)
执行代理对象方法的对象 —- 租房的人
流程:我们要租房—–>中介(租房的方法)——>房主(租房的方法)
抽象:调用对象—–>代理对象——>目标对象
动态代理的API:
在jdk的API中存在一个Proxy中存在一个生成动态代理的的方法newProxyInstance:

 

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

返回值:Object就是代理对象
参数:loader:代表与目标对象相同的类加载器—–目标对象.getClass().getClassLoader()
interfaces:代表与目标对象实现的所有的接口字节码对象数组
h:具体的代理的操作,InvocationHandler接口

 

栗子1:
目标对象接口:

public interface TargetInterface {
    public void method1();
    public String method2();
    public int method3(int x);
}

目标对象:

//目标对象
public class Target implements TargetInterface{
    @Override
    public void method1() {
        System.out.println("method1 running...");
    }
    @Override
    public String method2() {
        System.out.println("method2 running...");
        return "method2";
    }
    @Override
    public int method3(int x) {
        return x;
    }
}

 

代理对象:

 

//代理对象
public class ProxyTest {
    @Test
    public void test1(){
        //获得动态的代理对象----在运行时 在内存中动态的为Target创建一个虚拟的代理对象
        //objProxy是代理对象 根据参数确定到底是谁的代理对象
        TargetInterface objProxy = (TargetInterface) Proxy.newProxyInstance(
            Target.class.getClassLoader(),      //与目标对象相同的类加载器
            new Class[]{TargetInterface.class},
            new InvocationHandler() {
                    //invoke 代表的是执行代理对象的方法
                    @Override
                    //method:代表目标对象的方法字节码对象
                    //args:代表目标对象的响应的方法的参数
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("目标方法前的逻辑");
                        //执行目标对象的方法
                        Object invoke = method.invoke(new Target(), args);
                        System.out.println("目标方法后的逻辑");
                        return invoke;
                    }
            }
        );
        objProxy.method1();
        String method2 = objProxy.method2();
        //System.out.println(method2);
    }
}

 

运行结果: 
目标方法前的逻辑 
method1 running… 
目标方法后的逻辑 
目标方法前的逻辑 
method2 running… 
目标方法后的逻辑

栗子2:

package com.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyTest2 {
    public static void main(String[] args) {
        final Target target = new Target();
        //动态创建代理对象
        TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            new InvocationHandler() {
                @Override
                //被执行几次?------- 看代理对象调用方法几次
                //代理对象调用接口相应方法 都是调用invoke
                /*
                 * proxy:是代理对象
                 * method:代表的是目标方法的字节码对象
                 * args:代表是调用目标方法时参数
                 */
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //反射知识点
                    Object invoke = method.invoke(target, args);//目标对象的相应方法
                    //retrun返回的值给代理对象
                    return invoke;
                }
            }
        );
        //调用invoke---Method:目标对象的method1方法  args:null  返回值null
        proxy.method1();
        //调用invoke---Method:目标对象的method2方法  args:null  返回值method2
        String method2 = proxy.method2();
        ////调用invoke-----Method:目标对象的method3方法 args:Object[]{100}  返回值100
        int method3 = proxy.method3(100);
        System.out.println(method2);
        System.out.println(method3);

    }
}

运行结果: 
method1 running… 
method2 running… 
method2 
100

栗子3:全局编码

public class EncodingFilter implements Filter{
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                    throws IOException, ServletException {
        final HttpServletRequest req = (HttpServletRequest) request;
        //使用动态代理完成全局编码
        HttpServletRequest enhanceRequset = (HttpServletRequest) Proxy.newProxyInstance(
                req.getClass().getClassLoader(),
                req.getClass().getInterfaces(),
                new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            //对getParameter方法进行增强
                            String name = method.getName();//获得目标对象的方法名称
                            if("getParameter".equals(name)){
                                String invoke = (String) method.invoke(req, args);//乱码
                                //转码
                                invoke = new String(invoke.getBytes("iso8859-1"),"UTF-8");
                                return invoke;
                            }
                            return method.invoke(req, args);
                        }
                }
        );
        chain.doFilter(enhanceRequset, response);
    }
    @Override
    public void destroy() {

    }
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }
}

 

使用cglib代理:

 

public class UserServiceProxyFactory2 implements MethodInterceptor {
    public UserService getUserServiceProxy(){
        //帮我们生成代理对象
        Enhancer en = new Enhancer();
        //设置对谁进行代理
        en.setSuperclass(UserServiceImpl.class);
        //代理要做什么
        en.setCallback(this);
        //创建代理对象
        UserService us = (UserService) en.create();
        return us;
    }
    @Override
    public Object intercept(Object prxoyobj, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable {
        //打开事务
        System.out.println("打开事务!");
        //调用原有方法
        Object returnValue = methodProxy.invokeSuper(prxoyobj, arg);
        //提交事务
        System.out.println("提交事务!");
        return returnValue;
    }
}

 

代码测试:

@Test
    public void fun2(){
        UserServiceProxyFactory2 factory = new UserServiceProxyFactory2();
        UserService usProxy = factory.getUserServiceProxy();
        usProxy.save();
        //判断代理对象是否属于被代理对象类型
        //代理对象继承了被代理对象=>true
        System.out.println(usProxy instanceof UserServiceImpl );  //true
    }

运行结果:
打开事务!
保存用户!
提交事务!
true

2.2、Spring中的AOP名词解释

JoinPoint(连接点):目标对象中所有可以增强的方法。
PointCut(切入点):目标对象,已经增强的方法。
Advice(通知 / 增强):增强的代码。
Target(目标对象):被代理对象。
Weaving(织入):将通知应用到切入点的过程。
Proxy(代理):将通知织入到目标对象之后形成代理对象。
Aspect(切面):切入点+通知

2.3、Spring中的AOP演示

创建通知类:

 

//表示该类是一个通知类
public class MyAdvice {
    //前置通知
    public void before(){
        System.out.println("这是前置通知!!");
    }
    //后置通知
    public void afterReturning(){
        System.out.println("这是后置通知(如果出现异常不会调用)!!");
    }
    //环绕通知
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("这是环绕通知之前的部分!!");
        Object proceed = pjp.proceed();//调用目标方法
        System.out.println("这是环绕通知之后的部分!!");
        return proceed;
    }
    //异常通知
    public void afterException(){
        System.out.println("出事啦!出现异常了!!");
    }
    //后置通知
    public void after(){
        System.out.println("这是后置通知(出现异常也会调用)!!");
    }
}

 

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"
       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="domain"></context:component-scan>
    <context:component-scan base-package="aop"></context:component-scan>
    <!--1、配置目标对象,得到的是代理的对象-->
    <bean name="userServiceTarget" class="aop.service.UserServiceImpl"></bean>
    <!--2、配置通知对象-->
    <bean name="myAdvice" class="aop.advice.MyAdvice"></bean>
    <!--3、配置将通知织入目标对象-->
    <aop:config>
        <!-- 配置切入点
            public void cn.long.service.UserServiceImpl.save()
            void cn.long.service.UserServiceImpl.save()
            * cn.long.service.UserServiceImpl.save()
            * cn.long.service.UserServiceImpl.*()

            * cn.long.service.*ServiceImpl.*(..)
            * cn.long.service..*ServiceImpl.*(..)
        -->
        <aop:pointcut id="pc" expression="execution(* aop.service.UserServiceImpl.*(..))"></aop:pointcut>
        <aop:aspect ref="myAdvice" >
            <!-- 指定名为before方法作为前置通知 -->
            <aop:before method="before" pointcut-ref="pc"></aop:before>
            <!-- 后置 -->
            <aop:after-returning method="afterReturning" pointcut-ref="pc"></aop:after-returning>
            <!-- 环绕通知 -->
            <aop:around method="around" pointcut-ref="pc" />
            <!-- 异常拦截通知 -->
            <aop:after-throwing method="afterException" pointcut-ref="pc"></aop:after-throwing>
            <!-- 后置 -->
            <aop:after method="after" pointcut-ref="pc"></aop:after>
        </aop:aspect>
    </aop:config>
</beans>

 

测试:

package aop;

import aop.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:/spring-config.xml")
public class Demo {
    @Resource(name="userServiceTarget")
    private UserService us;

    @Test
    public void fun1(){
        us.save();
    }
}

运行结果: 
我是初始化方法这是前置通知!! 
这是环绕通知之前的部分!! 
保存用户! 
这是后置通知(出现异常也会调用)!! 
这是环绕通知之后的部分!! 
这是后置通知(如果出现异常不会调用)!! 
我是销毁方法

 

2.3、Spring中的AOP注解方式演示

 

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"
       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 name="userServiceTarget" class="aop.service.UserServiceImpl"></bean>
    <!--2、配置通知对象-->
    <bean name="myAdvice" class="aop.advice.MyAdvice2"></bean>
    <!-- 3.开启使用注解完成织入 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

 

通知:

package aop.advice;

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

//通知类
@Aspect
//表示该类是一个通知类
public class MyAdvice2 {
    @Pointcut("execution(* aop.service.UserServiceImpl.*(..))")
    public void pc(){}
    //前置通知
    //指定该方法是前置通知,并制定切入点
    @Before("MyAdvice2.pc()")
    public void before(){
        System.out.println("这是前置通知!!");
    }
    //后置通知
    @AfterReturning("execution(* aop.service.UserServiceImpl.*(..))")
    public void afterReturning(){
        System.out.println("这是后置通知(如果出现异常不会调用)!!");
    }
    //环绕通知
    @Around("execution(* aop.service.UserServiceImpl.*(..))")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("这是环绕通知之前的部分!!");
        Object proceed = pjp.proceed();//调用目标方法
        System.out.println("这是环绕通知之后的部分!!");
        return proceed;
    }
    //异常通知
    @AfterThrowing("execution(* aop.service.UserServiceImpl.*(..))")
    public void afterException(){
        System.out.println("出事啦!出现异常了!!");
    }
    //后置通知
    @After("execution(* aop.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("这是后置通知(出现异常也会调用)!!");
    }
}

测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:/aop/advice/spring-config.xml")
public class Demo {
    @Resource(name="userServiceTarget")
    private UserService us;
    @Test
    public void fun1(){
        us.save();
    }
}

运行结果: 
这是环绕通知之前的部分!! 
这是前置通知!! 
保存用户! 
这是环绕通知之后的部分!! 
这是后置通知(出现异常也会调用)!! 
这是后置通知(如果出现异常不会调用)!!

 

十一、JDBC模板对象

 

Spring整合了一个可以操作数据库的对象JDBCTemplate(JBDC模板对象),该对象封装了jdbc技术,与DBUtils中的QueryRunner非常相似。 
演示一下JDBCTemplate的使用:

 

//演示JDBC模板
public class Demo {
    @Test
    public void fun1() throws Exception {
        //0 准备连接池
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql:///test");
        dataSource.setUser("root");
        dataSource.setPassword("666");
        //1 创建JDBC模板对象
        JdbcTemplate jt = new JdbcTemplate();
        jt.setDataSource(dataSource);
        //2 书写sql,并执行
        String sql = "insert into user values(null,‘long‘) ";
        jt.update(sql);
    }
}

 

运行结果: 
技术分享图片 
JDBCTemplate增删改查: 
UserDao :

public interface UserDao {
    //
    void save(User u);
    //
    void delete(Integer id);
    //
    void update(User u);
    //
    User getById(Integer id);
    //
    int getTotalCount();
    //
    List<User> getAll();
}

UserDaoImpl:

//使用JDBC模板实现增删改查
public class UserDaoImpl extends JdbcDaoSupport implements UserDao {
    @Override
    public void save(User u) {
        String sql = "insert into t_user values(null,?) ";
        super.getJdbcTemplate().update(sql, u.getName());
    }
    @Override
    public void delete(Integer id) {
        String sql = "delete from t_user where id = ? ";
        super.getJdbcTemplate().update(sql,id);
    }
    @Override
    public void update(User u) {
        String sql = "update  t_user set name = ? where id=? ";
        super.getJdbcTemplate().update(sql, u.getName(),u.getId());
    }
    @Override
    public User getById(Integer id) {
        String sql = "select * from t_user where id = ? ";
        return super.getJdbcTemplate().queryForObject(sql,new RowMapper<User>(){
            @Override
            public User mapRow(ResultSet rs, int arg1) throws SQLException {
                User u = new User();
                u.setId(rs.getInt("id"));
                u.setName(rs.getString("name"));
                return u;
            }}, id);
    }
    @Override
    public int getTotalCount() {
        String sql = "select count(*) from t_user  ";
        Integer count = super.getJdbcTemplate().queryForObject(sql, Integer.class);
        return count;
    }
    @Override
    public List<User> getAll() {
        String sql = "select * from t_user  ";
        List<User> list = super.getJdbcTemplate().query(sql, new RowMapper<User>(){
            @Override
            public User mapRow(ResultSet rs, int arg1) throws SQLException {
                User u = new User();
                u.setId(rs.getInt("id"));
                u.setName(rs.getString("name"));
                return u;
            }});
        return list;
    }
}

将其配置到Spring容器中: 
依赖关系: 
技术分享图片 
配置文件如下:

 

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

    <!-- 指定spring读取db.properties配置 -->
    <context:property-placeholder location="classpath:db.properties"  />

    <!-- 1.将连接池放入spring容器 -->
    <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}" ></property>
        <property name="driverClass" value="${jdbc.driverClass}" ></property>
        <property name="user" value="${jdbc.user}" ></property>
        <property name="password" value="${jdbc.password}" ></property>
    </bean>

    <!-- 2.将JDBCTemplate放入spring容器 -->
    <bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
        <property name="dataSource" ref="dataSource" ></property>
    </bean>

    <!-- 3.将UserDao放入spring容器 -->
    <bean name="userDao" class="jdbcTemplate.UserDaoImpl" >
        <!-- <property name="jt" ref="jdbcTemplate" ></property> -->
        <property name="dataSource" ref="dataSource" ></property>
    </bean>

</beans>

 

测试:

package jdbcTemplate;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

/**
 * Created by KPL on 2018/7/1.
 */
//演示JDBC模板
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-config.xml")
public class Demo {
    @Resource(name="userDao")
    private UserDao ud;
    @Test
    public void fun2() throws Exception{
        User u = new User();
        u.setName("naruto");
        ud.save(u);
    }
    @Test
    public void fun3() throws Exception{
        User u = new User();
        u.setId(2);
        u.setName("jack");
        ud.update(u);

    }
    @Test
    public void fun4() throws Exception{
        ud.delete(2);
    }
    @Test
    public void fun5() throws Exception{
        System.out.println(ud.getTotalCount());
    }
    @Test
    public void fun6() throws Exception{
        System.out.println(ud.getById(1));
    }
    @Test
    public void fun7() throws Exception{
        System.out.println(ud.getAll());
    }
}

运行结果: 
技术分享图片 
public class UserDaoImpl extends JdbcDaoSupport继承了JdbcDaoSupport,Spring会根据连接池自动创建JDBC模板对象。也就是说不需要手动擦行间JBDC模板对象,从父类方法中直接获取即可。

 

String sql = "insert into t_user values(null,?) ";
super.getJdbcTemplate().update(sql, u.getName());

 

此时,配置文件修改成如下:

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

    <!-- 指定spring读取db.properties配置 -->
    <context:property-placeholder location="classpath:db.properties"  />

    <!-- 1.将连接池放入spring容器 -->
    <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}" ></property>
        <property name="driverClass" value="${jdbc.driverClass}" ></property>
        <property name="user" value="${jdbc.user}" ></property>
        <property name="password" value="${jdbc.password}" ></property>
    </bean>

    <!-- 3.将UserDao放入spring容器 -->
    <bean name="userDao" class="jdbcTemplate.UserDaoImpl" >
        <property name="dataSource" ref="dataSource" ></property>
    </bean>

</beans>

 

十二、Spring事务管理

1.1、事务概述
(1)什么是事务?
一件事情有n个组成单元 要不这n个组成单元同时成功,要不n个单元就同时失败
就将n个组成单元放到一个事务中。
(2)mysql的事务
默认的事务:一条sql语句就是一个事务 默认就开启事务并提交事务。sql执行完了之后自动提交了。
手动事务:
    显示的开启一个事务:start transaction。
    事务提交:commit代表从开启事务到事务提交,中间的所有的sql都认为有效真正的更新数据库。
    事务的回滚:rollback代表事务的回滚从开启事务到事务回滚中间的所有的sql操作都认为无效数据库没有被更新。

1.2、JDBC事务操作
默认是自动事务:
    执行sql语句:executeUpdate() —- 每执行一次executeUpdate方法代表事务自动提交。
通过jdbc的API手动事务:
    开启事务:conn.setAutoComnmit(false);
    提交事务:conn.commit();
    回滚事务:conn.rollback();
注意:控制事务的connnection必须是同一个执行sql的connection与开启事务的connnection必须是同一个才能对事务进行控制。

1.3、DBUtils事务操作
QueryRunner
  有参构造:QueryRunner runner = new QueryRunner(DataSource dataSource);
    有参构造将数据源(连接池)作为参数传入QueryRunner,QueryRunner会从连接池中获得一个数据库连接资源操作数据库,所以直接使用无Connection参数的update方法即可操作数据库。不需要事务则采用此方法。
    无参构造:QueryRunner runner = new QueryRunner();
    无参的构造没有将数据源(连接池)作为参数传入QueryRunner,那么我们在使用QueryRunner对象操作数据库时要使用有Connection参数的方法。此方法能实现事务。

 

1.4、事务的特性ACID
(1)原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作 要么都发生,要么都不发生。
(2)一致性(Consistency)一个事务中,事务前后数据的完整性必须保持一致。
(3)隔离性(Isolation)多个事务,事务的隔离性是指多个用户并发访问数据库时,一个用户的 事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。
(4)持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变 就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

五、事务的隔离
如果不考虑隔离性,事务存在3种并发访问问题。
脏读:B事务读取到了A事务尚未提交的数据 —— 要求B事务要读取A事务提交的数据
不可重复读:一个事务中 两次读取的数据的内容不一致 —– 要求的是一个事务中多次读取时数据是一致的 — unpdate
幻读/虚读:一个事务中 两次读取的数据的数量不一致 —– 要求在一个事务多 次读取的数据的数量是一致的 –insert delete
事务的隔离级别:
(1)read uncommitted : 读取尚未提交的数据 :哪个问题都不能解决
(2)read committed:读取已经提交的数据 :可以解决脏读 —- oracle默认的
(3)repeatable read:重读读取:可以解决脏读和不可重复读 —mysql默认的
(4)serializable:串行化:可以解决脏读不可重复读和虚读—相当于锁表
注意:mysql数据库默认的隔离级别
查看mysql数据库默认的隔离级别:select @@tx_isolation
设置mysql的隔离级别:set session transaction isolation level 设置事务隔离级别

 

因为在不用平台,操纵事务的代码各不相同,于是Spring提供了一个接口PlatfromTransactionManager接口,针对不同的平台,提供不同的实现类。

***** 真正管理事务的对象
org.springframework.jdbc.datasource.DataSourceTransactionManager 
//使用 SpringJDBC 或 iBatis 进行持久化数据时使用
org.springframework.orm.hibernate3.HibernateTransactionManager 
//使用Hibernate 版本进行持久化数据时使用

事务的传播行为:决定业务方法之间调用,事务应该如何处理。

//保证同一个事务中
PROPAGATION_REQUIRED 支持当前事务,如果不存在 就新建一个(默认)
PROPAGATION_SUPPORTS 支持当前事务,如果不存在,就不使用事务
PROPAGATION_MANDATORY 支持当前事务,如果不存在,抛出异常
//保证没有在同一个事务中
PROPAGATION_REQUIRES_NEW 如果有事务存在,挂起当前事务,创建一个新的事务
PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果有事务存在,挂起当前事务
PROPAGATION_NEVER 以非事务方式运行,如果有事务存在,抛出异常
PROPAGATION_NESTED 如果当前事务存在,则嵌套事务执行

演示一下Spring事务: 
先完成基本的转账功能: 
Dao:

package Transaction.dao;

public interface AccountDao {
    //加钱
    void increaseMoney(Integer id, Double money);
    //减钱
    void decreaseMoney(Integer id, Double money);
}

DaoImpl:

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao  {
    @Override
    public void increaseMoney(Integer id, Double money) {
        getJdbcTemplate().update("update t_account set money = money+? where id = ? ", money,id);
    }
    @Override
    public void decreaseMoney(Integer id, Double money) {
        getJdbcTemplate().update("update t_account set money = money-? where id = ? ", money,id);
    }
}

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

    <!-- 指定spring读取db.properties配置 -->
    <context:property-placeholder location="classpath:db.properties"  />

    <!-- 1.将连接池 -->
    <bean name="dataSource1" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}" ></property>
        <property name="driverClass" value="${jdbc.driverClass}" ></property>
        <property name="user" value="${jdbc.user}" ></property>
        <property name="password" value="${jdbc.password}" ></property>
    </bean>
    <!-- 2.Dao-->
    <bean name="accountDao" class="Transaction.dao.AccountDaoImpl" >
        <property name="dataSource" ref="dataSource1" ></property>
    </bean>
    <!-- 3.Service-->
    <bean name="accountService" class="Transaction.service.AccountServiceImpl" >
        <property name="ad" ref="accountDao" ></property>
    </bean>
</beans>

测试类:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-config2.xml")
public class Demo {
    @Resource(name="accountService")
    private AccountService as;
    @Test
    public void fun1(){
        as.transfer(1, 2, 100d);
    }
}

运行结果: 
技术分享图片 
现在开始加事务: 
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"
       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">

<!-- 指定spring读取db.properties配置 -->
<context:property-placeholder location="classpath:db.properties"  />

<!-- 事务核心管理器,封装了所有事务操作. 依赖于连接池 -->
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
    <property name="dataSource" ref="dataSource1" ></property>
</bean>

<!-- 事务模板对象 -->
<bean name="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate" >
    <property name="transactionManager" ref="transactionManager" ></property>
</bean>

<!-- 1.将连接池 -->
<bean name="dataSource1" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
    <property name="jdbcUrl" value="${jdbc.jdbcUrl}" ></property>
    <property name="driverClass" value="${jdbc.driverClass}" ></property>
    <property name="user" value="${jdbc.user}" ></property>
    <property name="password" value="${jdbc.password}" ></property>
</bean>
<!-- 2.Dao-->
<bean name="accountDao" class="Transaction.dao.AccountDaoImpl" >
    <property name="dataSource" ref="dataSource1" ></property>
</bean>
<!-- 3.Service-->
<bean name="accountService" class="Transaction.service.AccountServiceImpl" >
    <property name="ad" ref="accountDao" ></property>
    <property name="tt" ref="transactionTemplate" ></property>
</bean>
</beans>

ServiceImpl:

@Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED,readOnly=true)
public class AccountServiceImpl implements AccountService {
    private AccountDao ad ;
    private TransactionTemplate tt;
    @Override
    public void transfer(final Integer from,final Integer to,final Double money) {
        tt.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus arg0) {
                //减钱
                ad.decreaseMoney(from, money);
                int i = 1/0;
                //加钱
                ad.increaseMoney(to, money);
            }
        });
    }

    public void setAd(AccountDao ad) {
        this.ad = ad;
    }

    public void setTt(TransactionTemplate tt) {
        this.tt = tt;
    }
}

测试代码:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-config2.xml")
public class Demo {
    @Resource(name="accountService")
    private AccountService as;
    @Test
    public void fun1(){
        as.transfer(1, 2, 100d);
    }
}

运行结果,由于加入了事务,报错之后,钱并不会转过去: 
技术分享图片 
XML配置(aop) 
Spring内部已经封装了事务通知方法,那么咱们只需要将它配置到业务处理上去就可以了。

 

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

    <!-- 指定spring读取db.properties配置 -->
    <context:property-placeholder location="classpath:db.properties"  />

    <!-- 事务核心管理器,封装了所有事务操作. 依赖于连接池 -->
    <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
        <property name="dataSource" ref="dataSource" ></property>
    </bean>
    <!-- 事务模板对象 -->
    <bean name="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate" >
        <property name="transactionManager" ref="transactionManager" ></property>
    </bean>

    <!-- 配置事务通知 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager" >
        <tx:attributes>
            <!-- 以方法为单位,指定方法应用什么事务属性
                isolation:隔离级别
                propagation:传播行为
                read-only:是否只读
             -->
            <tx:method name="save*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
            <tx:method name="persist*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
            <tx:method name="update*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
            <tx:method name="modify*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
            <tx:method name="delete*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
            <tx:method name="remove*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
            <tx:method name="get*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true" />
            <tx:method name="find*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true" />
            <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
        </tx:attributes>
    </tx:advice>

    <!-- 配置织入 -->
    <aop:config  >
        <!-- 配置切点表达式 -->
        <aop:pointcut expression="execution(* Transaction.service.*ServiceImpl.*(..))" id="txPc"/>
        <!-- 配置切面 : 通知+切点
                 advice-ref:通知的名称
                 pointcut-ref:切点的名称
         -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPc" />
    </aop:config>

    <!-- 1.将连接池 -->
    <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}" ></property>
        <property name="driverClass" value="${jdbc.driverClass}" ></property>
        <property name="user" value="${jdbc.user}" ></property>
        <property name="password" value="${jdbc.password}" ></property>
    </bean>

    <!-- 2.Dao-->
    <bean name="accountDao" class="Transaction.dao.AccountDaoImpl" >
        <property name="dataSource" ref="dataSource" ></property>
    </bean>
    <!-- 3.Service-->
    <bean name="accountService" class="Transaction.service.AccountServiceImpl" >
        <property name="ad" ref="accountDao" ></property>
        <property name="tt" ref="transactionTemplate" ></property>
    </bean>

</beans>

 

注解配置(aop)

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

    <!-- 指定spring读取db.properties配置 -->
    <context:property-placeholder location="classpath:db.properties"  />

    <!-- 事务核心管理器,封装了所有事务操作. 依赖于连接池 -->
    <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
        <property name="dataSource" ref="dataSource" ></property>
    </bean>
    <!-- 事务模板对象 -->
    <bean name="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate" >
        <property name="transactionManager" ref="transactionManager" ></property>
    </bean>

    <!-- 开启使用注解管理aop事务 -->
    <tx:annotation-driven/>

    <!-- 1.将连接池 -->
    <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}" ></property>
        <property name="driverClass" value="${jdbc.driverClass}" ></property>
        <property name="user" value="${jdbc.user}" ></property>
        <property name="password" value="${jdbc.password}" ></property>
    </bean>

    <!-- 2.Dao-->
    <bean name="accountDao" class="Transaction.dao.AccountDaoImpl" >
        <property name="dataSource" ref="dataSource" ></property>
    </bean>
    <!-- 3.Service-->
    <bean name="accountService" class="Transaction.service.AccountServiceImpl" >
        <property name="ad" ref="accountDao" ></property>
        <property name="tt" ref="transactionTemplate" ></property>
    </bean>

</beans>

加入注解:

@Transactional(isolation= Isolation.REPEATABLE_READ,propagation= Propagation.REQUIRED,readOnly=true)
public class AccountServiceImpl implements AccountService {
    private AccountDao ad ;
    private TransactionTemplate tt;

    @Override
    @Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED,readOnly=false)
    public void transfer(final Integer from,final Integer to,final Double money) {
        //减钱
        ad.decreaseMoney(from, money);
        int i = 1/0;
        //加钱
        ad.increaseMoney(to, money);
    }
    public void setAd(AccountDao ad) {
        this.ad = ad;
    }

    public void setTt(TransactionTemplate tt) {
        this.tt = tt;
    }
}

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-config4.xml")
public class Demo {
    @Resource(name="accountService")
    private AccountService as;
    @Test
    public void fun1(){
        as.transfer(1, 2, 100d);
    }
}

运行结果,由于出错,钱不会转过去: 
技术分享图片

 

 

 

 

 

 

 

 

 




























































































































以上是关于Spring学习的主要内容,如果未能解决你的问题,请参考以下文章

Spring boot:thymeleaf 没有正确渲染片段

What's the difference between @Component, @Repository & @Service annotations in Spring?(代码片段

spring练习,在Eclipse搭建的Spring开发环境中,使用set注入方式,实现对象的依赖关系,通过ClassPathXmlApplicationContext实体类获取Bean对象(代码片段

Spring Rest 文档。片段生成时 UTF-8 中间字节无效 [重复]

IOS开发-OC学习-常用功能代码片段整理

java SpringRetry学习的代码片段