超详细Spring入门讲解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/endlessseaofcrow/article/details/79519493

1.基本内容

  • spring是为了解决企业应用开发的复杂性而创建的,是一个轻量级的控制反转(IoC)[指的是将对象的创建权反转给Spring,作用是实现了程序的解耦合]和面向切面(AOP)的容器框架。
  • 并不局限于某一层,是对象的容器,帮我们“管理”项目中所有的对象

2.操作

2.1快速入门

  • 架包结构
docs:API和开发规范 
libs:包  --> .jar包  javadoc.jar 文档  sources.jar 源码
schema:约束
  • 1.导包

日志包

com.springsource.org.apache.commons.logging-1.1.1.jar

可选日志包(老版本)

com.springsource.org.apache.log4j-1.2.15.jar
  • 2.创建一个对象
package com.sjtu.bean;
public class User {
    private  String name;
    private Integer age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
}
  • 3.书写配置注册对象到容器

    • 建立xml文件,建议放在src下,文件名建议applicationContext.xml

    • 导入约束

    • Preference–>XML Catalog–>Add–>FileSystem–>Spring目录下的Schema–>beans–>选择最新版

    • 在 Add XML Catalog Elementy页面 ,key type选择Schema location,key后面加上刚才添加的文件名。(意义是eclipse单机情况下也能找到该约束)

    • 在applicationContext.xml页面加入<beans></beans> ,然后点击左下角的Design,选中beans,右键Edit namespaces ,添加xsi 文件xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance",再点add,选择Specify New Namespace ,选择Browse ,选择 Select XML Catalog entry ,选择刚才导入的 http://www.springframework.org/schema/beans/spring-beans-4.2.xsd ,Namespace Name 为http://www.springframework.org/schema/beans ,Prefix为空

    • 配置xml文件
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd ">
    <!--将User对象交给spring容器管理  ,其中name任意,class为全包名-->
    <bean name="user" class="com.sjtu.bean.User"></bean>
    </beans>
  • 4.代码测试

@Test
public void fun1() {
  //1.创建容器对象,相对于src下的路径
  ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
  //2.向容器“要”user对象
  User u=(User) ac.getBean("user");
  //3.打印user对象
  System.out.println(u);
}

3.概念

3.1IOC&DI

  • IOC

  • DI:

3.2applicationContext&BeanFactory

  • BeanFactory 接口
    • spring原始接口.最底层的接口。针对原始接口的实现类功能较为单一
    • BeanFactory接口实现类的容器.特点是每次在获得对象时才会创建对象,为了节省内存
  • ApplicationContext
    • 每次容器启动时就会创建容器中配置的所有对象.并提供更多功能
    • 从类路径下加载配置文件:ClassPathXmlApplicationContext
    • 从硬盘绝对路径下加载配置文件:FileSystemXmlApplicationContext(“d:/xxx/yyy/xxx”)

结论:web开发中,使用applicationContext. 在资源匮乏的环境(手机)可以使用BeanFactory.

4.配置详解

4.1Bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd ">
    <!--将User对象交给spring容器管理  ,其中name任意,class为全包名
        class属性:被管理对象的完整类名
        name属性:给被管理的对象起个名字,根据该名称获得对象
            可以重复,可以使用特殊字符
        id属性:与name属性一模一样
            名称不可重复,不能使用特殊字符
        结论:尽量使用name属性
    -->
    <bean name="user" class="com.sjtu.bean.User"></bean>
</beans>

4.2Spring创建对象的三种方式

  • 1.空参构造方式(最主要方式)
<!--创建方式1:空参构造创建  -->
 <bean name="user" class="com.sjtu.bean.User"></bean>
//1.创建容器对象,相对于src下的路径
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
  • 2.静态工厂(了解)
public static User createUser() {
        System.out.println("静态工厂创建User");//表示由用户自己创建
        return new User();
    }
<!--创建方式2:静态工厂创建方式  
        调用UserFactory的createUser方法创建名为user2的对象,放入容器
    -->
    <bean name="user2" 
        class="com.sjtu.b_create.UserFactory"  //类的全包名
        factory-method="createUser"></bean>     //类的方法
//测试
public void fun2() {
ApplicationContext ac=new ClassPathXmlApplicationContext("com/sjtu/b_create/applicationContext.xml");
//2.向容器“要”user对象
User u=(User) ac.getBean("user2");
    }
  • 3.实例工厂(了解)
public  User createUser2() {//不是静态方法
        System.out.println("实例工厂创建User");
        return new User();
    }
    <!--创建方式3:实例工厂创建
            调用UserFactory对象的createUser2方法创建名为user3的对象,放入容器
          -->
    <bean name="user3" 
        factory-bean="userFactory"
        factory-method="createUser2"></bean>
    <bean name="userFactory" 
        class="com.sjtu.b_create.UserFactory" ></bean>
public void fun3() {
        ApplicationContext ac=new ClassPathXmlApplicationContext("com/sjtu/b_create/applicationContext.xml");
        //2.向容器“要”user对象
        User u=(User) ac.getBean("user3");

    }

4.3 Bean元素进阶

4.3.1 scope属性
  • singleton(默认值):单例对象,被标识为单例的对象在spring容器中只会存在一个实例
<bean name="user" class="com.sjtu.bean.User" scope="singleton"></bean>
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
//2.向容器“要”user对象
User u=(User) ac.getBean("user");
User u2=(User) ac.getBean("user");
User u3=(User) ac.getBean("user");
User u4=(User) ac.getBean("user");
//3.打印user对象 会发现只有一个实例
System.out.println(u==u3);
System.out.println(u2==u4);
  • prototype:多例原型,被标识为多例的对象,每次再获得時才会获得对象,每次都是新的的对象。整合Struts时,ActionBean必须配置为多例。
  • request:web环境下,对象与request生命周期一致 (了解)
  • session:web环境下,对象与session生命周期一致 (了解)
4.3.2生命周期属性(了解)
  • 配置一个方法作为生命周期初始化方法.spring会在对象创建之后立即调用.
    • init-method
  • 配置一个方法作为生命周期的销毁方法.spring容器在关闭并销毁所有容器中的对象之前调用.
    • destory-method
<bean name="user" class="com.sjtu.bean.User" scope="singleton" init-method="init" destroy-method="destroy"></bean>
//并在User中实现此方法
public void init() {
        System.out.println("初始化");
    }

    public void destroy() {
        System.out.println("销毁");
    }

4.4分模块配置

主配置文件引入其他配置文件

//在主配置文件中做如下配置
<import resource="com/sjtu/b_create/applicationContext.xml"/>

4.5.属性注入

属于配置方法

  • set方法注入(重要)(前提是set注入之前该对象提供setter方法)
<bean name="user" class="com.sjtu.bean.User" >
    <!--值类型注入:为User对象中名为name的属性注入tom作为值-->
    <property name="name" value="tom"></property>
    <property name="age" value="18"></property>
    <!--引用类型注入:为car属性注入下方配置的car对象   car是user中一个对象-->
    <property name="car" ref="car"></property>
  </bean>
  <!--将car对象配置到容器中 -->
  <bean name="car" class="com.sjtu.bean.Car">
    <property name="name" value="兰博基尼"></property>
    <property name="color" value="黄色"></property>
</bean>
  • 构造函数注入

    • 准备带有参数的构造

    • <bean name="user2" class="com.sjtu.bean.User">
          <!-- name属性:构造函数参数名 -->
          <!-- index属性:构造函数参数索引  -->
          <!-- type属性:构造函数参数类型 -->
          <!-- 上述三个属性不必全部出现,根据情况选择即可 -->
          <constructor-arg name="name"  value="Jerry" index="0" type="java.lang.String"></constructor-arg>
          <constructor-arg name="car" ref="car"></constructor-arg>
      </bean>

  • p名称空间注入(了解)

<!-- p空间注入   走set方法
        1.导入p空间名称 xmlns:p="http://www.springframework.org/schema/p"
        2.使用p:属性完成注入
            |-值类型 : p:属性名="值"
            |-对象类型:p:属性名-ref="bean名称"
      -->
    <bean name="user3" class="com.sjtu.bean.User"    p:name="jack" p:age="20" p:car-ref="car">  
    </bean>

<!--car对象-->
<!--将car对象配置到容器中 -->
    <bean name="car" class="com.sjtu.bean.Car">
        <property name="name" value="兰博基尼"></property>
        <property name="color" value="黄色"></property>
    </bean>
  • spel注入(了解)

    <!-- spel注入:Spring Expression Language  spring表达式语言-->
    <bean name="user4" class="com.sjtu.bean.User" >
        <property name="name" value="#{user.name}"></property>
        <property name="age" value="#{user3.age}"></property>
        <property name="car" ref="car"></property>
    </bean>

4.6复杂类型注入

  • 数组,list,map等等
public class CollectionBean {
    private Object[] arr;//数组类型注入
    private List list;//list/set类型注入
    private Map map;//map注入
    private Properties prop;// Properties 类型注入
}
  • 数组
<bean name="cb"  class="com.sjtu.c_injection.CollectionBean">
        <!-- 如果数组中只准备一个值(对象),直接使用value|ref即可 -->
        <!-- 对象中数组名为arr -->
        <!-- <property name="arr" value="Tom"></property> -->
        <property name="arr">
            <array>
                <value>tom</value>
                <value>jerry</value>
                <ref bean="car"/>
            </array>
        </property>
</bean>
  • list
<!-- 如果list中只准备一个值(对象),直接使用value|ref即可 -->
        <!-- <property name="list" value="Tom"></property> -->
        <property name="list">
            <list>
                <value>tom</value>
                <value>Jerry</value>
                <ref bean="car"/>
            </list>
        </property>
  • map
<property name="map">
            <map>
                <entry key="1" value="abc"></entry>
                <entry key="2" value="def"></entry>
                <entry key-ref="car" value-ref="car"></entry>
            </map>
        </property>
  • prop
<property name="prop">
            <props>
                <prop key="abc">abc</prop>
                <prop key="def">def</prop>
                <prop key="ghi">ghi</prop>
            </props>
        </property>

5.整合web项目


6.使用注解配置spring

6.1步骤

  • 1.为主配置文件引入新的命名空间(约束)

    • 加入context,和之前快速入门完全一样,只是在添加namespace时,prefix不能为空。
    • 导入spring下的aop包
  • 2.开启使用注解代替配置文件

<?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" 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 ">
    <!-- 指定扫描com.sjtu.bean包下的所有类中的注解
        注意:扫描包时,会扫描指定包下的所有子孙包 -->
    <context:component-scan base-package="com.sjtu.bean"></context:component-scan>
</beans>
  • 3.类中完成注解配置
@Component("user") //这四个注解完全一样,以下三个只是为了分层
    @Service("user")  //Service层
    @Controller("user")  //Web层
    @Repository("user")  //Dao层
public class User {
}
  • 4.代码测试
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
User u=(User) ac.getBean("user");
System.out.println(u);

6.2其他注解说明

  • scope
//指定对象作用范围
@Scope(scopeName="prototype")
public class User {}
  • 值注入类型
//方法一
@Value("Tom")
//加到成员变量上,通过反射的Field赋值,破坏封装性
private  String name;
//方法二
@Value("Tom")
//通过set方法赋值
public void setName(String name) {
  this.name = name;
}
  • 引用类型引入

    @Autowired//自动装配
    //问题,如果匹配多个类型一致的对象,将无法选择具体注入哪一对象
    @Qualifier("car")//使用@Qualifier注解告诉spring容器自动装配哪个名称的对象
    public Car car;
    @Resource(name="car") //手动注入,指定注入哪个名称的对象
    public Car car;
    
    @Component("car")
    public class Car {
    @Value("法拉利")
    private String name;
    @Override
    public String toString() {
        return "Car [name=" + name + "]";
    }
    }

  • 初始化、销毁方法

    @PostConstruct //在对象被创建之后调用,init-method
    public void init() {
        System.out.println("初始化");
    }
    @PreDestroy //在对象销毁之前调用,destroy-method
    public void destroy() {
        System.out.println("初始化");
    }

7.STS插件

8.spring与junit整合测试

  • 导包(4+2+aop+test)
  • 配置注解
//创建容器
@RunWith(SpringJUnit4ClassRunner.class)
//指定容器使用配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class Deom {
    //将名为user的对象注入u变量中
    @Resource(name="user")
    private User u;
    @Test
    public void fun1() {
        System.out.println(u);
    }
}

9.aop

9.1aop思想

  • 横向重复,纵向抽取

9.2Spring中的aop

  • Spring能够为容器中管理的对象生成动态代理对象
  • 以前我们要使用动态代理,我们需要自己调用下面的方法生成对象Proxy.newProxyInstance(xx,xx,xx) 生成代理对象,Spring能够帮我们生成代理对象
9.2.1Spring实现aop原理
  • 动态代理(优先)
    • 被代理对象必须要实现实现接口,才能产生代理对象。如果没有接口不能使用动态代理技术。
  • cglib代理(没有接口使用)
    • 第三方代理技术,cglib代理,可以对任何类实现代理,代理的原理是对目标对象进行继承代理。如果目标对象被final修饰,该类无法被cglib代理。

9.3aop名词解释

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

10.aop演示(XML配置)

  • 1.导包(4+2+2(spring_aop+spring_aspects)+2(com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar;com.springsource.org.aopalliance-1.0.0.jar))
  • 2.准备目标对象
public class UserServiceImpl implements UserService{
    @Override
    public void save() {
        System.out.println("保存");
    }
    @Override
    public void delete() {
        System.out.println("删除");
    }
    @Override
    public void update() {
        System.out.println("更新");
    }
    @Override
    public void find() {
        System.out.println("查找");
    }
}
  • 3.准备通知
    • 前置通知 目标方法之前调用
    • 后置通知 (如果出现异常不会调用) 在目标方法运行之后
    • 环绕通知 在目标方法之前和之后都调用
    • 异常拦截通知 如果出现异常,就会调用
    • 后置通知 (无论是否出现异常都会调用) 在目标方法运行之后调用
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("这是后置通知(出现异常也会调用)");
    }
}
  • 4.配置进行织入,将通知织入目标对象中
    • 导入aop约束
    • xml文件中添加命名空间
<?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" 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 ">
<!-- 准备工作:导入aop(约束)命名空间 -->
<!-- 1.配置目标对象 -->
    <bean name="userService" class="com.sjtu.proxy.UserServiceImpl"></bean>
<!-- 2.配置通知对象 -->
    <bean name="myAdvice" class="com.sjtu.proxy.MyAdvice"></bean>   
<!-- 3.配置将通知织入切入点对象 -->
    <aop:config>
    <!-- 配置切入点 
        public void com.sjtu.proxy.UserServiceImpl.save()
         void com.sjtu.proxy.UserServiceImpl.save()
         * com.sjtu.proxy.UserServiceImpl.save()
         * com.sjtu.proxy.UserServiceImpl.*()

         * com.sjtu.proxy.*ServiceImpl.*(..)
         * com.sjtu.proxy..*ServiceImpl.*(..)
    -->
    <aop:pointcut expression="execution(* com.sjtu.proxy..*ServiceImpl.*(..))" id="pc"/>
        <aop:aspect ref="myAdvice">
            <!-- 指定为before方法作为前置通知 -->
            <aop:before method="before" pointcut-ref="pc"/>
            <!-- 后置 -->
            <aop:after method="after" pointcut-ref="pc"/> 
            <!-- 环绕通知 -->
            <aop:around method="around" pointcut-ref="pc"/>
            <!-- 异常拦截通知 -->
            <aop:after-throwing method="afterException" pointcut-ref="pc"/>
            <!-- 后置 -->
            <aop:after-returning method="afterReturning" pointcut-ref="pc"/>
        </aop:aspect>
    </aop:config>
</beans>
  • 5.代码测试
//创建容器
@RunWith(SpringJUnit4ClassRunner.class)
//指定容器使用配置文件
@ContextConfiguration("classpath:com/sjtu/springaop/applicationContext.xml")
public class Deom {

    //将名为user的对象注入u变量中
    @Resource(name="userService")
    private UserService us;

    @Test
    public void fun1() {

        System.out.println(us);
        us.save();
    }
}

11.aop演示(注解)

  • 1.导包

  • 2.准备目标对象

  • 3.准备通知

  • 4.注解

    <?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" 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 ">
    <!-- 准备工作:导入aop(约束)命名空间 -->
    <!-- 1.配置目标对象 -->
        <bean name="userService" class="com.sjtu.proxy.UserServiceImpl"></bean>
    <!-- 2.配置通知对象 -->
        <bean name="myAdvice" class="com.sjtu.proxy.MyAdvice"></bean>   
    <!-- 3.注解配置 -->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    </beans>
    //表示是一个通知类
    @Aspect
    public class MyAdvice {
    
        @Pointcut("execution(* com.sjtu.proxy..*ServiceImpl.*(..))")
        public void pc() {}
    
        //前置通知
        //指定方法是前置通知,并制定切入点
        @Before("MyAdvice.pc()")
        public void before() {
            System.out.println("这是前置通知!");
        }
        //后置通知
        @AfterReturning("execution(* com.sjtu.proxy..*ServiceImpl.*(..))")
        public void afterReturning() {
            System.out.println("这是后置通知(如果出现异常不会调用)");
        }
        //环绕通知
        @Around("execution(* com.sjtu.proxy..*ServiceImpl.*(..))")
        public Object around(ProceedingJoinPoint pjp) throws Throwable {
            System.out.println("这是环绕通知之前的部分!");
            Object proceed = pjp.proceed();
            System.out.println("这是环绕通知之后的部分!");
            return proceed;
        }
        //异常通知
        @AfterThrowing("execution(* com.sjtu.proxy..*ServiceImpl.*(..))")
        public void afterException() {
            System.out.println("异常出现了!");
        }
        //后置通知
        @After("execution(* com.sjtu.proxy..*ServiceImpl.*(..))")
        public void after() {
            System.out.println("这是后置通知(出现异常也会调用)");
        }
    }
    
  • 5.代码测试

12.Spring整合JDBC

12.1JDBCTemplate

  • spring中提供了一个可以操作数据库的对象,对象封装了jdbc技术。
  • 与DBUtils中QueryRunner非常相似
  • 与DBUtils中的QueryRunner非常相似
//C3P0的连接池设定
//1.准备连接池
ComboPooledDataSource dataSource=new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/spring");    
dataSource.setUser("root");
dataSource.setPassword("123456");
//2.创建JDBC模板对象
JdbcTemplate jTemplate=new JdbcTemplate();
jTemplate.setDataSource(dataSource);
//3.书写sql,并执行
String sql="insert into t_user values(null,'babdd')";
jTemplate.update(sql);

12.2 JDBCTemplate连接数据库

  • 1.导包:
    • 4(spring-beans+spring-context+spring-core+spring-expression)+2(spring-logging+spring-log4j)
    • 与Junit整合(spring-test+spring-aop)
    • JDBC驱动+C3P0连接池
    • spring-jdbc+spring-tx事务
  • 2.准备数据库
  • 3.书写Dao
    • uqdate
    • query(sql, rse, args);
    • queryForObject(sql, rse, args);
//使用JDBC模板实现增删改查
public class UserDaoIml implements UserDao{

  //并且给jTemplate设置setter方法
    private JdbcTemplate jTemplate;
    @Override
    public void save(User u) {
        String sql="insert into t_user values(null,?)";
        jTemplate.update(sql, u.getName());
    }

    @Override
    public void delete(Integer id) {
        String sql="delete from t_user where id=?";
        jTemplate.update(sql, id);
    }

    @Override
    public void update(User u) {
        String sql="update t_user set name=? where id=?";
        jTemplate.update(sql, u.getName(),u.getId());
    }

    @Override
    public User getById(Integer id) {
        String sql="select * from t_user where id=?";
        return jTemplate.queryForObject(sql, new RowMapper<User>() {

            @Override
            public User mapRow(ResultSet rs, int arg1) throws SQLException {
                User user=new User();
                user.setId(rs.getInt("id"));
                user.setName(rs.getString("name"));
                return user;
            }}, id);
    }

    @Override
    public int getTotalCount() {
        String sql="select count(*) from t_user";
        Integer count = jTemplate.queryForObject(sql, Integer.class);
        return count;
    }

    @Override
    public List<User> getAll() {
        String sql="select * from t_user";
        return jTemplate.query(sql,new RowMapper<User>() {

            @Override
            public User mapRow(ResultSet rs, int arg1) throws SQLException {
                User user=new User();
                user.setId(rs.getInt("id"));
                user.setName(rs.getString("name"));
                return user;
            }});
    }

    public void setjTemplate(JdbcTemplate jTemplate) {
        this.jTemplate = jTemplate;
    }
}


  • 4.spring配置

    • 依赖关系
    • 注意三者的依赖关系,UserDaoImpl需要jdbcTemplate,jdbcTemplate需要datasource连接池,根据依赖关系,从下往上配置,显示dataSource连接池,再是jdbcTemplate,最后是UserDao
    <?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" 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 ">
    <!-- 1.将连接池放入spring容器中 -->
    <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="jdbcUrl" value="jdbc:mysql:///spring"></property>
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="user" value="root"></property>
        <property name="password" value="123456"></property>
    </bean>
    <!-- 2.将JDBCTemplate放入spring容器中 -->
      <!--JDBCTemplate需要datasource连接池 -->
    <bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 3.将UserDao放入spring容器中 -->
      <!--UserDaoIml需要jdbctemplate-->
    <bean name="userDao" class="com.sjtu.template.UserDaoIml">
        <property name="jTemplate" ref="jdbcTemplate"></property>   
    </bean>
    </beans>
  • 5.测试

package com.sjtu.test;

import javax.annotation.Resource;

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

import com.sjtu.bean.User;
import com.sjtu.template.UserDao;

//创建容器
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo {

    //将名为userDao的对象注入ud变量中
        @Resource(name="userDao")
    private UserDao ud;

    @Test
    public void fun1() {
        User u=new User();
        u.setName("Jerry");
        ud.save(u);
    }
    @Test
    public void fun2() {

        ud.delete(1);
    }
    @Test
    public void fun3() {
        User u=new User();
        u.setId(4);
        u.setName("YYY");

        ud.update(u);
    }
    @Test
    public void fun4() {

        System.out.println(ud.getById(4));
    }
    @Test
    public void fun5() {

        System.out.println(ud.getAll());
    }

}
  • 6.继承JDBCDaoSupport

    • 根据连接池创建JDBC模板
    • 不需要手动准备JDBC模板,从父类方法中获得即可
    • xml中不需要配置模板了
    package com.sjtu.template;
    
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.List;
    
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.core.RowMapper;
    import org.springframework.jdbc.core.support.JdbcDaoSupport;
    
    import com.sjtu.bean.User;
    //使用JDBC模板实现增删改查
    
    public class UserDaoIml 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 user=new User();
                user.setId(rs.getInt("id"));
                user.setName(rs.getString("name"));
                return user;
            }}, 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";
        return super.getJdbcTemplate().query(sql,new RowMapper<User>() {
    
            @Override
            public User mapRow(ResultSet rs, int arg1) throws SQLException {
                User user=new User();
                user.setId(rs.getInt("id"));
                user.setName(rs.getString("name"));
                return user;
            }});
    }
    }
    
    <?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" 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 ">
    <!-- 1.将连接池放入spring容器中 -->
    <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="jdbcUrl" value="jdbc:mysql:///spring"></property>
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="user" value="root"></property>
        <property name="password" value="123456"></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="com.sjtu.template.UserDaoIml">
        <!-- <property name="jTemplate" ref="jdbcTemplate"></property>   -->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    </beans>
  • 7.改进:使用配置文件

db.properties 在src目录下

 jdbc.jdbcUrl=dbc:mysql:///spring
 jdbc.driverClass=com.mysql.jdbc.Driver
 jdbc.user=root
 jdbc.password=123456
<?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" 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 ">
    <!-- 0.读取配置文件 -->
    <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="com.sjtu.template.UserDaoIml">
        <!-- <property name="jTemplate" ref="jdbcTemplate"></property>   -->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
</beans>

13.Spring与事务

13.1事务的概念

  • 回顾知识

    1. 事务特性

    2. 事务并发问题

    3. 事务的隔离级别
  • 事务操作对象

    • spring封装了事务管理的代码:打开事务,提交事务,回滚事务。
    • 因为在不同平台,操作事务的代码各不相同,spring提供了一个接口PlatformTransactionManager 接口,里面有许多实现类:如JDBC–DataSourceTransactionManager,在spring中事务管理最为核心的对象:TransactionManager
    • 事务的隔离级别,1.读未提交;2.读已提交;3.可重复读;4.串行化
    • 是否只读,true(只读) false
    • 事务传播行为:决定业务方法之间调用,事务该如何处理。有七种,默认为PROPAGION_REQUIRED:支持当前事务,如果不存在,就新建一个(默认,99.9%以上概率)

13.2事务环境准备

  • 1.接口
package com.ali.dao;

public interface AccountDao {

    //加钱
    void increaseMoney(Integer id, Double money);
    //减钱
    void decreaseMoney(Integer id,Double money);

}
  • 2.准备数据库
  • 3.实现接口
import org.springframework.jdbc.core.support.JdbcDaoSupport;

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {

    @Override
    public void increaseMoney(Integer id, Double money) {
        super.getJdbcTemplate().update("update t_account set money =money+? where id=?",money,id);

    }

    @Override
    public void decreaseMoney(Integer id, Double money) {
        // TODO Auto-generated method stub
        super.getJdbcTemplate().update("update t_account set money =money-? where id=?",money,id);
    }

}
  • 4.service层配置
package com.ali.service;

public interface AccountService {

    void transfer(Integer from ,Integer to,Double money);
}

package com.ali.service;

import com.ali.dao.AccountDao;

public class AccountServiceImpl implements AccountService {

    //注意此名字要与xml中的名字一致,否则无法注入
    private AccountDao accountDao;
    @Override
    public void transfer(Integer from, Integer to, Double money) {
        // TODO Auto-generated method stub
        ad.decreaseMoney(from, money);
        ad.increaseMoney(to, money);
    }

    //set方法注入,
    public void setAccountDao(AccountDao aDao) {
        this.accountDao = aDao;
    }
}

  • 5.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-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 ">
    <!-- 1.dataSource -->
    <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="jdbcUrl" value="jdbc:mysql:///spring"></property>
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="user" value="root"></property>
        <property name="password" value="123456"></property>
    </bean>
    <!-- 2.dao -->
    <bean name="accountDao" class="com.ali.dao.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 3.service -->
    <bean name="accountService" class="com.ali.service.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>
</beans>
  • 6.事务管理:xml配置;注释配置

    • 配置事务的核心管理器,依赖于连接池
    </bean>
    <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    • xml配置

      • 此时,通知由SpringAop提供,代理对象account已经写好,还有织入(配置)就可以完成。

      • 导包:4+2+2(aop+aspect)+aop联盟+weaving织入包

      • 导入新的约束(tx)

        • beans:最基本的 context:注解,读取properties配置 aop:配置aop tx:配置事务空间
      • 配置通知

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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>
          <!-- 配置事务通知 -->
          <tx:advice id="txAdvice" transaction-manager="transactionManager">
              <tx:attributes>
                  <!-- 以方法为单位,指定方法应用什么事务属性
                  isolation:隔离级别
                  propagation:传播行为
                  read-only:是否只读
               -->
                  <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" /><!-- 指定方法 -->
                  <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:attributes>
          </tx:advice>
          <!-- 配置织入 -->
          <aop:config>
              <!-- 配置切点表达式 -->
              <aop:pointcut expression="execution(* com.ali.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="com.ali.dao.AccountDaoImpl">
              <property name="dataSource" ref="dataSource"></property>
          </bean>
          <!-- 3.service -->
          <bean name="accountService" class="com.ali.service.AccountServiceImpl">
              <property name="accountDao" ref="accountDao"></property>
          </bean>
      </beans>
    • 代码测试

  • 注解配置

    • 导包

    • 引入新的约束(tx)

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

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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>
          <!-- 开启使用注解管理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="com.ali.dao.AccountDaoImpl">
              <property name="dataSource" ref="dataSource"></property>
          </bean>
          <!-- 3.service -->
          <bean name="accountService" class="com.ali.service.AccountServiceImpl">
              <property name="accountDao" ref="accountDao"></property>
          </bean>
      </beans>
      • 注解(注意:注解在类上加可以,在方法上加也可以)

        public class AccountServiceImpl implements AccountService {
        private AccountDao accountDao;
        @Override
        @Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED,readOnly=false)
        public void transfer(Integer from, Integer to, Double money) {
            // TODO Auto-generated method stub
            accountDao.decreaseMoney(from, money);
            accountDao.increaseMoney(to, money);
        }
        //set方法注入
        public void setAccountDao(AccountDao aDao) {
            this.accountDao = aDao;
        }
        }
      • 代码测试

        
        @RunWith(SpringJUnit4ClassRunner.class)
        @ContextConfiguration("classpath:applicationContext2.xml")
        public class Demo2 {
        
            @Autowired
            private AccountService aService;
            @Test
            public void fun1() {
                aService.transfer(1, 2, 100d);
            }
        }

展开阅读全文

没有更多推荐了,返回首页