Lesson36_Spring

36 篇文章 0 订阅
1 篇文章 0 订阅

Spring

  • struts:web层,比较简单(ValueStack值栈,拦截器)
  • hibernate:dao层,知识点杂
  • spring:service层,重要,讲多少用多少 --> 【了解】
    spring
  • spring day01:基础(IoC控制反转、DI依赖注入)、整合Junit、整合web
  • spring day02:AOP切面编程、JdbcTemplate
  • spring day03:事务管理、SSH整合

1、 spring框架概述

1.1 什么是spring

  • Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。
  • 轻量级:与EJB对比,依赖资源少,销毁的资源少。
  • 分层: 一站式,每一个层都提供的解决方案
    • web层:struts,spring-MVC
    • service层:spring
    • dao层:hibernate,mybatis , jdbcTemplate --> spring-data
  • 历史:
    1. 2002年,首次推出了Spring框架的雏形:interface21框架
    2. Spring框架即以interface21框架为基础经过重新设计,并不断丰富其内涵,与2004年3月24日,发布了1.0正式版
  • Spring理念:简化企业级开发,使现有的技术更容易使用。本身是一个大杂烩,整合了现有的框架。

1.2 spring由来

  • Expert One-to-One J2EE Design and Development
  • Expert One-to-One J2EE Development without EJB

1.3 spring核心

  • Spring的核心是控制反转(IoC)面向切面(AOP)

1.4 spring优点

  • 方便解耦,简化开发 (高内聚低耦合)
  1. Spring就是一个大工厂(容器),可以将所有对象创建和依赖关系维护,交给Spring管理
  2. spring工厂是用于生成bean
  • AOP编程的支持
  1. Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
  • 声明式事务的支持
  1. 只需要通过配置就可以完成对事务的管理,而无需手动编程
  • 方便程序的测试
  1. Spring对Junit4支持,可以通过注解方便的测试Spring程序
  • 方便集成各种优秀框架
  1. Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
  • 降低JavaEE API的使用难度
  1. Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低

1.5 spring体系结构

spring体系结构
核心容器:beans、core、context、expression

2、 入门案例:IoC【掌握】

2.1 问题引入

在传统开发中实现
  1. 我们做dao的开发,后续可能会出现将mysql数据库替换为Oracle的情况,所以我们给dao定义了一个接口,而写了两个实现类,这也是我们平时在dao以及service中定义接口的原因
    public interface UserDao {
    	void save();
    }
    public class UserDaoMysqlImpl {
    	public void save() {
    		System.out.println("mysql实现添加");
    	}
    }
    public class UserDaoOracleImpl {
    	public void save() {
    		System.out.println("oracle实现添加");
    	}
    }
    
  2. 此时我们在service调用或者使用测试类模拟,会发现,当前类跟两个实现类产生了耦合关系,后续如果要更改实现类,需要更改当前类的代码
    public class Demo{
    	UserDao userDao;
    	@Test
    	public void test01() {
    		userDao = new UserDaoMysqlImpl();
    		userDao.save();
    	}
    	@Test
    	public void test02() {
    		userDao = new UserDaoMysqlImpl();
    		userDao.save();
    	}
    }
    
  3. 针对上面这种传统开发出现的问题,我们能想到的解决办法就是使用工厂帮我们创建实现类的实例,从而将当前类跟实现类的耦合关系降低,下面我们写两个静态方法模拟工厂类
    public class UserDaoFactory {
    	public static UserDao get01() {
    		return new UserDaoMysqlImpl();
    	}
    	public static UserDao get02() {
    		return new UserDaoMysqlImpl();
    	}
    }
    
  4. 此时我使用工厂实现替换
    public class Demo{
    	UserDao userDao;
    	@Test
    	public void test01() {
    		userDao = new UserDaoMysqlImpl();
    		userDao.save();
    	}
    	@Test
    	public void test02() {
    		userDao = new UserDaoMysqlImpl();
    		userDao.save();
    	}
    	@Test
    	public void test03() {
    		userDao = UserDaoFactory.get01();
    		userDao.save();
    	}
    	@Test
    	public void test04() {
    		userDao = UserDaoFactory.get02();
    		userDao.save();
    	}
    }
    
  5. spring也是利用这种思想,采用了工厂+反射+xml的形式,实现了控制反转,如下:
    在这里插入图片描述

2.2 导入jar包

  • 4 + 1 : 4个核心(beans、core、context、expression) + 1个依赖(commons-loggins…jar)

2.3 目标类

  • 提供UserService接口和实现类
  • 获得UserService实现类的实例
    之前开发中,直接new一个对象即可。
    学习spring之后,将由Spring创建对象实例–> IoC 控制反转(Inverse of Control)之后需要实例对象时,从spring工厂(容器)中获得,需要将实现类的全限定名称配置到xml文件中
	public interface UserService {
		public void addUser();
		}
public class UserServiceImpl implements UserService {
	@Override
	public void addUser() {
		System.out.println("a_ico add user");
	}
}

2.4 配置文件

  • 位置:任意,开发中一般在classpath下(src)
  • 名称:任意,开发中常用applicationContext.xml
  • 内容:添加schema约束
    约束文件位置:spring-framework-3.2.0.RELEASE\docs\spring-framework-reference\html\ xsd-config.html
<?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">
	<!-- 配置service 
		<bean> 配置需要创建的对象
			id :用于之后从spring容器获得实例时使用的
			class :需要创建实例的全限定类名
	-->
	<bean id="userServiceId" class="com.itheima.a_ioc.UserServiceImpl"></bean>
</beans>

2.5 测试

	@Test
	public void demo02(){
		//从spring容器获得
		//1 获得容器
		String xmlPath = "com/itheima/a_ioc/beans.xml";
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
		//2获得内容 --不需要自己new,都是从spring容器获得
		UserService userService = (UserService) applicationContext.getBean("userServiceId");
		userService.addUser();
	}

3、 入门案例:DI【掌握】

  • DI Dependency Injection ,依赖注入
    is a :是一个,继承。
    has a:有一个,成员变量,依赖。
    class B {
    private A a; //B类依赖A类
    }
    依赖:一个对象需要使用另一个对象
    注入:通过setter方法进行另一个对象实例设置。
  • 例如:
	class BookServiceImpl{
        //之前开发:接口 = 实现类  (service和dao耦合)
		//private BookDao bookDao = new BookDaoImpl();
 		//spring之后 (解耦:service实现类使用dao接口,不知道具体的实现类)
		private BookDao bookDao;
		setter方法
   }
   模拟spring执行过程
   创建service实例:BookService bookService = new BookServiceImpl()		-->IoC  <bean>
   创建dao实例:BookDao bookDao = new BookDaoImple()				-->IoC
   将dao设置给service:bookService.setBookDao(bookDao);				-->DI   <property>

3.1 目标类

  1. 创建BookService接口和实现类
  2. 创建BookDao接口和实现类
  3. 将dao和service配置 xml文件
  4. 使用api测试
3.1.1 dao
public interface BookDao {
	public void addBook();
}
public class BookDaoImpl implements BookDao {
	@Override
	public void addBook() {
		System.out.println("di  add book");
	}
}
3.1.2 service
public interface BookService {
   public abstract void addBook();
}
public class BookServiceImpl implements BookService {
   // 方式1:之前,接口=实现类
//	private BookDao bookDao = new BookDaoImpl();
   // 方式2:接口 + setter
   private BookDao bookDao;
   public void setBookDao(BookDao bookDao) {
   	this.bookDao = bookDao;
   }
   @Override
   public void addBook(){
   	this.bookDao.addBook();
   }
}

3.2 配置文件

<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">
	<!-- 
	模拟spring执行过程
		创建service实例:BookService bookService = new BookServiceImpl()	IoC  <bean>
		创建dao实例:BookDao bookDao = new BookDaoImpl()			IoC
		将dao设置给service:bookService.setBookDao(bookDao);		DI   <property>
		
		<property> 用于进行属性注入
			name: bean的属性名,通过setter方法获得
				setBookDao ##> BookDao  ##> bookDao
			ref :另一个bean的id值的引用
	 -->

	<!-- 创建service -->
	<bean id="bookServiceId" class="com.itheima.b_di.BookServiceImpl">
		<property name="bookDao" ref="bookDaoId"></property>
	</bean>
	
	<!-- 创建dao实例 -->
	<bean id="bookDaoId" class="com.itheima.b_di.BookDaoImpl"></bean>
	
</beans>

3.3 测试

	@Test
	public void demo01(){
		//从spring容器获得
		String xmlPath = "com/itheima/b_di/beans.xml";
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
		BookService bookService = (BookService) applicationContext.getBean("bookServiceId");
		bookService.addBook();
	}

4、 myeclipse schema xml提示

  • 步骤一:确定xsd文件位置
    spring-framework-3.2.0.RELEASE\schema\beans

  • 步骤二:复制路径

  • 步骤三:搜索“xml catalog”

  • 步骤四:添加约束提示

5、 核心API

  • api整体了解,之后不使用,在学习过程需要。
    核心API
  • BeanFactory :这是一个工厂,用于生成任意bean。早期使用。
    采取延迟加载,第一次getBean时才会初始化Bean
  • ApplicationContext:是BeanFactory的子接口,继承了BeanFactory功能更强大。(扩展了包括国际化处理、事件传递、Bean自动装配、各种不同应用层的Context实现)。当配置文件被加载,就将所有bean(对象)实例化。
    ClassPathXmlApplicationContext 用于加载classpath(类路径、src)下的xml
    加载xml运行时位置 --> /WEB-INF/classes/…xml
    FileSystemXmlApplicationContext 用于加载指定盘符下的xml
    加载xml运行时位置 --> /WEB-INF/…xml
    通过java web ServletContext.getRealPath() 获得具体盘符
	@Test
	public void demo02(){
		//使用BeanFactory  --第一次条用getBean实例化
		String xmlPath = "com/itheima/b_di/beans.xml";
		
		BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource(xmlPath));
		
		BookService bookService = (BookService) beanFactory.getBean("bookServiceId");
		
		bookService.addBook();
		
	}

6、 装配Bean 基于XML

6.1 实例化方式

  • 3种bean实例化方式:默认构造、静态工厂、实例工厂
6.1.1 默认构造
  • <bean id=“” class=“”> 必须提供默认构造
6.1.2 静态工厂
  • 常用与spring整合其他框架(工具)
  • 静态工厂:用于生成实例对象,所有的方法必须是static
    <bean id=“” class=“工厂全限定类名” factory-method=“静态方法”>
6.1.2.1 工厂
public class MyBeanFactory {
	
	/**
	 * 创建实例,么有参数
	 * @return
	 */
	public static UserService createService(){
		return new UserServiceImpl();
	}
	/**
	 * 创建实例,有参数
	 * @return
	 */
	public static String getStr(String str){
		return str;
	}
}
6.1.2.2 spring配置
	<!-- 将静态工厂创建的实例交予spring 
		class 确定静态工厂全限定类名
		factory-method 确定静态方法名
	-->
	<bean id="userServiceId" class="com.itheima.c_inject.b_static_factory.MyBeanFactory" factory-method="createService"></bean>
	<!--
		如果静态工厂中的方法是需要参数的。那么就需要通过类似于构造的方法。通过<constructor-arg value=“值”>的方式传入进去
	-->
	<bean id="getStr" class="com.itheima.c_inject.b_static_factory.MyBeanFactory" factory-method="getStr">
		<constructor-arg value=“abc”></constructor-arg>
	</bean>
6.1.3 实例工厂
  • 实例工厂:必须先有工厂实例对象,通过实例对象创建对象。提供所有的方法都是“非静态”的。
6.1.3.1 工厂
/**
 * 实例工厂,所有方法非静态
 *
 */
public class MyBeanFactory {
	
	/**
	 * 创建实例
	 * @return
	 */
	public UserService createService(){
		return new UserServiceImpl();
	}
}
6.1.3.2 spring配置
	<!-- 创建工厂实例 -->
	<bean id="myBeanFactoryId" class="com.itheima.c_inject.c_factory.MyBeanFactory"></bean>
	<!-- 获得userservice 
		* factory-bean 确定工厂实例
		* factory-method 确定普通方法
	-->
	<bean id="userServiceId" factory-bean="myBeanFactoryId" factory-method="createService"></bean>

6.2 Bean种类

  • 普通bean:之前操作的都是普通bean。<bean id=“” class=“A”> ,spring直接创建A实例,并返回
  • FactoryBean:是一个特殊的bean,具有工厂生成对象能力,只能生成特定的对象。
    bean必须使用 FactoryBean接口,此接口提供方法 getObject() 用于获得特定bean。
    <bean id=“” class=“FB”> 先创建FB实例,使用调用getObject()方法,并返回方法的返回值
    FB fb = new FB();
    return fb.getObject();
  • BeanFactory 和 FactoryBean 对比?
    BeanFactory:工厂,用于生成任意bean。
    FactoryBean:特殊bean,用于生成另一个特定的bean。例如:ProxyFactoryBean ,此工厂bean用于生产代理。<bean id=“” class=“…ProxyFactoryBean”> 获得代理对象实例。AOP使用

6.3 作用域

  • 作用域:用于确定spring创建bean实例个数
    作用域
  • 取值:
    singleton 单例的,默认值。
    prototype 原型的(多例),每执行一次getBean将获得一个实例。例如:struts整合spring,配置action多例。
    request:每次request请求创建一个bean,放在request中,作用于一个request,不同的request是不同的bean
    session:与request类似,只是作用于一次会话。而不是请求。不同的会话使用不同的session
    globalSession:主要应用于分布式
  • 配置信息
    <bean id=“” class=“” scope=“”>

6.4 生命周期

我们在使用ApplicationContext时,bean的初始化是在加载配置文件时,这也是跟BeanFactory的区别
我们可以手动创建空构造。查看bean被初始化的时机。
而销毁是在调用close方法的时候,而ApplicationContext是没有close方法的,必须是ClassPathXmlApplicationContext这个类才有,所以在加载配置文件时,不能用多态。
bean的销毁实际就是在bean容器销毁时被销毁。
bean的整个生命周期都是被spring监控的。
在这里插入图片描述
上面说的生命周期针对单例bean,而Spring我们在配置bean的时候就默认都是单例的。
而如果不是单例的。Spring只负责bean的初始化操作。不负责销毁操作。

6.4.1 初始化和销毁
  • 目标方法执行前后执行后,将进行初始化或销毁。
    <bean id=“” class=“” init-method=“初始化方法名称” destroy-method=“销毁的方法名称”>
6.4.1.1 目标类
public class UserServiceImpl implements UserService {

	@Override
	public void addUser() {
		System.out.println("e_lifecycle add user");
	}
	
	public void myInit(){
		System.out.println("初始化");
	}
	public void myDestroy(){
		System.out.println("销毁");
	}

}
6.4.1.2 spring配置
<!--  
		init-method 用于配置初始化方法,准备数据等
		destroy-method 用于配置销毁方法,清理资源等
	-->
	<bean id="userServiceId" class="com.itheima.e_lifecycle.UserServiceImpl" 
		init-method="myInit" destroy-method="myDestroy" ></bean>
6.4.1.3 测试
@Test
	public void demo02() throws Exception{
		//spring 工厂
		String xmlPath = "com/itheima/e_lifecycle/beans.xml";
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
		UserService userService = (UserService) applicationContext.getBean("userServiceId");
		userService.addUser();
		
		//要求:1.容器必须close,销毁方法执行; 2.必须是单例的
//		applicationContext.getClass().getMethod("close").invoke(applicationContext);
		// * 此方法接口中没有定义,实现类提供
		applicationContext.close();
		
	}
6.4.1.4 多例

前面我们展示了bean的生命周期,发现从初始化到销毁整个流程都是被Spring监控的
而此时我们如果修改bean的score。变为多例的时候再执行同样的操作
会发现bean实例被使用之后,虽然我们调用了close方法销毁了容器,但是bean实例没有被销毁。
也就是说多例的情况下,后面的销毁操作Spring不再负责 。

6.4.1.5 Bean属性介绍
  1. ID:给bean起名字,具有约束性,名称不能重复
  2. class:需要创建的实例,一般在项目中属于耦合的代码
  3. name:给bean起名称,作用于id一样,如果没有id,可以通过name获取,理论可以重复,实际也不能重复
  4. init-method:指定初始化方法
  5. destroy-method:指定销毁方法
  6. factory-bean:指定工厂
  7. factory-method:指定工厂中的方法
6.4.2 BeanPostProcessor 后处理Bean
  • spring 提供一种机制,只要实现此接口BeanPostProcessor,并将实现类提供给spring容器,spring容器将自动执行,在初始化方法前执行before(),在初始化方法后执行after() 。 配置<bean class=“”>
Object postProcessAfterInitialiration(Object bean,String beanName)
			Apply this BeanpostProcessor to the given new bean ircustom init-method).
Object postProcessBeforeInitialiration(Object bean,String beanName)
  • Factory hook(勾子) that allows for custom modification of new bean instances, e.g. checking for marker interfaces or wrapping them with proxies.
  • spring提供工厂勾子,用于修改实例对象,可以生成代理对象,是AOP底层。
    模拟
    A a =new A();
    a = B.before(a) --> 将a的实例对象传递给后处理bean,可以生成代理对象并返回。
    a.init();
    a = B.after(a);

a.addUser(); //生成代理对象,目的在目标方法前后执行(例如:开启事务、提交事务)

a.destroy()

6.4.2.1 编写实现类
public class MyBeanPostProcessor implements BeanPostProcessor {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("前方法 : " + beanName);
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
		System.out.println("后方法 : " + beanName);
		// bean 目标对象
		// 生成 jdk 代理
		return Proxy.newProxyInstance(
					MyBeanPostProcessor.class.getClassLoader(), 
					bean.getClass().getInterfaces(), 
					new InvocationHandler(){
						@Override
						public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
							
							System.out.println("------开启事务");
							
							//执行目标方法
							Object obj = method.invoke(bean, args);
							
							System.out.println("------提交事务");
							return obj;
						}});
	}
}
6.4.2.2 配置
<!-- 将后处理的实现类注册给spring -->
	<bean class="com.itheima.e_lifecycle.MyBeanPostProcessor"></bean>
  • 问题1:后处理bean作用某一个目标类,还是所有目标类?
    所有
  • 问题2:如何只作用一个?
    通过“参数2”beanName进行控制

6.5 属性依赖注入

  • 依赖注入方式:手动装配 和 自动装配
  • 手动装配:一般进行配置信息都采用手动
    基于xml装配:构造方法、setter方法
    基于注解装配:
  • 自动装配:struts和spring 整合可以自动装配
    byType:按类型装配
    byName:按名称装配
    constructor构造装配,
    auto: 不确定装配。
6.5.1 构造方法
6.5.1.1 目标类
public class User {
	
	private Integer uid;
	private String username;
	private Integer age;
	
	public User(Integer uid, String username) {
		super();
		this.uid = uid;
		this.username = username;
	}
	
	public User(String username, Integer age) {
		super();
		this.username = username;
		this.age = age;
	}
6.5.1.2 spring配置
	<!-- 构造方法注入 
		* <constructor-arg> 用于配置构造方法一个参数argument
			name :参数的名称
			value:设置普通数据
			ref:引用数据,一般是另一个bean id值
			
			index :参数的索引号,从0开始 。如果只有索引,匹配到了多个构造方法时,默认使用第一个。
			type :确定参数类型
		例如:使用名称name
			<constructor-arg name="username" value="jack"></constructor-arg>
			<constructor-arg name="age" value="18"></constructor-arg>
		例如2:【类型type 和  索引 index】
			<constructor-arg index="0" type="java.lang.String" value="1"></constructor-arg>
			<constructor-arg index="1" type="java.lang.Integer" value="2"></constructor-arg>
	-->
	<bean id="userId" class="com.itheima.f_xml.a_constructor.User" >
		<constructor-arg index="0" type="java.lang.String" value="1"></constructor-arg>
		<constructor-arg index="1" type="java.lang.Integer" value="2"></constructor-arg>
	</bean>
6.5.2 setter方法
<!-- setter方法注入 
		* 普通数据 
			<property name="" value="值">
			等效
			<property name="">
				<value>值
		* 引用数据
			<property name="" ref="另一个bean">
			等效
			<property name="">
				<ref bean="另一个bean"/>
		
		* 内部bean,注意内部bean在外面不能 被引用
			<property name="">
				<bean id="" class="另一个bean的class">
					<property name="另一个bean的属性" value="">
	-->
	<bean id="personId" class="com.itheima.f_xml.b_setter.Person">
		<property name="pname" value="阳志"></property>
		<property name="age">
			<value>1234</value>
		</property>
		
		<property name="homeAddr" ref="homeAddrId"></property>
		<property name="companyAddr">
			<ref bean="companyAddrId"/>
		</property>
	</bean>
	
	<bean id="homeAddrId" class="com.itheima.f_xml.b_setter.Address">
		<property name="addr" value="阜南"></property>
		<property name="tel" value="911"></property>
	</bean>
	<bean id="companyAddrId" class="com.itheima.f_xml.b_setter.Address">
		<property name="addr" value="北京八宝山"></property>
		<property name="tel" value="120"></property>
	</bean>
6.5.3、自动装配
<bean id="homeAddrId" class="com.itheima.f_xml.b_setter.Address">
		<property name="addr" value="阜南"></property>
		<property name="tel" value="911"></property>
	</bean>
	<bean id="companyAddrId" class="com.itheima.f_xml.b_setter.Address">
		<property name="addr" value="北京八宝山"></property>
		<property name="tel" value="120"></property>
	</bean>
<bean id="personId" class="com.itheima.f_xml.b_setter.Person">
		<property name="pname" value="阳志"></property>
		<property name="age">
			<value>1234</value>
		</property>
		
		<property name="homeAddr" ref="homeAddrId"></property>
		<property name="companyAddr">
			<ref bean="companyAddrId"/>
		</property>
</bean>
<!--
上面是手动装配,下面是自动装配:
autowire="bytype"是指自动装配,不用显示的注入属性
bytype:根据类型注入,文件中只能有一种需要的类型,比如需要一个homeAddress,就只能有一个类型
byname:根据名字注入,是根据setter方法的参数名自动查找文件上下文中对应名字的bean来实现注入
auto:不确定
-->
<bean id="personId" class="com.itheima.f_xml.b_setter.Person" autowire="bytype">
		<property name="pname" value="阳志"></property>
		<property name="age">
			<value>1234</value>
		</property>
</bean>

在于mybatis的整合中,service中写了setter方法或者构造以后,可以用自动装配完成依赖注入

    <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="typeAliasesPackage" value="com.iotek.entity"/>
        <property name="dataSource" ref="datasource"/>
        <property name="mapperLocations" value="classpath*:com/iotek/dao/*.xml"/>
    </bean>
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sessionFactory"/>
        <property name="basePackage" value="com.iotek.dao"/>
    </bean>
	<!-- 可以根据名称或者类型完成 自动装配-->
    <bean id="userService" class="com.iotek.service.impl.UserServiceImpl" autowire="byName" />
</beans>

autowir五种自动装配模式:
NO:不使用自动装配,应该显示装配。
byName:由属性名自动装配,在spring容器中寻找与属性名相同的bean进行装配。
byType:由属性的数据类型自动装配,在spring容器中寻找与属性类型相同的bean进行关联,如果有多个类型相同的bean,则会报错。只能有一个相匹配的。如果有相同类型的多个参数,都会进行匹配。
constructor:该类型只适用于构造函数参数类型。与byType类似,只不过用于构造注入
default:默认值,指不使用自动注入

自动装配局限性:

  1. 如果同时有显示装配和自动装配,显示装配会覆盖自动装配
  2. 自动装配无法注入基本数据类型或者String类型
  3. 精确性没有显示装配高,效率也略低
6.5.4 P命令空间[了解]
  • 对“setter方法注入”进行简化,替换,而是在
    <bean p:属性名=“普通值” p:属性名-ref=“引用值”>
  • p命名空间使用前提,必须添加命名空间
xmlns:p="http://www.springframework.org/schema/p"
	<bean id="personId" class="com.itheima.f_xml.c_p.Person" 
		p:pname="禹太璞" p:age="22" 
		p:homeAddr-ref="homeAddrId" p:companyAddr-ref="companyAddrId">
	</bean>
	
	<bean id="homeAddrId" class="com.itheima.f_xml.c_p.Address"
		p:addr="DG" p:tel="东莞">
	</bean>
	<bean id="companyAddrId" class="com.itheima.f_xml.c_p.Address"
		p:addr="DG" p:tel="岛国">
	</bean>
6.5.5、C命名空间

与p命名空间一样,p命名空间是用于setter方法注入,可以理解为是property,c命名空间是用于构造方法注入。所有必须提供有参的构造方法

	<bean id="personId" class="com.itheima.f_xml.c_p.Person" 
		c:pname="禹太璞" p:age="22" 
		c:homeAddr-ref="homeAddrId" c:companyAddr-ref="companyAddrId">
	</bean>
	
	<bean id="homeAddrId" class="com.itheima.f_xml.c_p.Address"
		c:addr="DG" c:tel="东莞">
	</bean>
	<bean id="companyAddrId" class="com.itheima.f_xml.c_p.Address"
		c:addr="DG" c:tel="岛国">
	</bean>
6.5.6 SpEL[了解]
  • 对进行统一编程,所有的内容都使用value

    #{123}、#{‘jack’} : 数字、字符串
    #{beanId} :另一个bean引用
    #{beanId.propName} :操作数据,另一个bean的属性值
    #{beanId.toString()} :执行方法,另一个bean的方法执行结果
    #{T(类).字段|方法} :静态方法或字段
	<!-- 
		<property name="cname" value="#{'jack'}"></property>
		<property name="cname" value="#{customerId.cname.toUpperCase()}"></property>
			通过另一个bean,获得属性,调用的方法
		<property name="cname" value="#{customerId.cname?.toUpperCase()}"></property>
			?.  如果对象不为null,将调用方法
	-->
	<bean id="customerId" class="com.itheima.f_xml.d_spel.Customer" >
		<property name="cname" value="#{customerId.cname?.toUpperCase()}"></property>
		<property name="pi" value="#{T(java.lang.Math).PI}"></property>
	</bean>
  • 阅读:spring_表达式.pdf
6.5.5 集合注入
<!-- 
		集合的注入都是给<property>添加子标签
			数组:<array>
			List:<list>
			Set:<set>
			Map:<map> ,map存放k/v 键值对,使用<entry>描述
			Properties:<props>  <prop key=""></prop>  【】
			
		普通数据:<value>
		引用数据:<ref>
	-->
	<bean id="collDataId" class="com.itheima.f_xml.e_coll.CollData" >
		<property name="arrayData">
			<array>
				<value>DS</value>
				<value>DZD</value>
				<value>屌丝</value>
				<value>屌中屌</value>
			</array>
		</property>
		
		<property name="listData">
			<list>
				<value>于嵩楠</value>
				<value>曾卫</value>
				<value>杨煜</value>
				<value>曾小贤</value>
			</list>
		</property>
		
		<property name="setData">
			<set>
				<value>停封</value>
				<value>薄纸</value>
				<value>关系</value>
			</set>
		</property>
		
		<property name="mapData">
			<map>
				<entry key="jack" value="杰克"></entry>
				<entry>
					<key><value>rose</value></key>
					<value>肉丝</value>
				</entry>
			</map>
		</property>
		
		<property name="propsData">
			<props>
				<prop key="高富帅"></prop>
				<prop key="白富美"></prop>
				<prop key="男屌丝"></prop>
			</props>
		</property>
	</bean>
6.5.6 集合命名空间

相当于将内部的集合,提取出来,类似于
将内部bean放到外面

<!--
	集合的命名空间都是util。如下:
	* list集合:<util:list id="xxx">
	* set集合:<util:set id="xxx">
	* map集合:<util:map id="xxx">
	定义id,在需要的地方直接引用
-->
<util:list>
	<!-- 集合元素可以引用其他bean -->
	<ref bean="被引用的id"/>
</util:list>
<bean id="userDao" class="com.iotek.dao.UserDaoImpl">
	<!-- 有集合属性,直接引用上面的集合即可 -->
	<property name="list" ref="xxx"/>
</bean>

7、 Spring对dao层jdbc支持对应后面JdbcTemplate

7.1 只使用数据源

  1. 引入对应的jar包,spring-jdbc和数据库驱动包
  2. 在Spring配置文件中配置数据源,DriverManagerDataSource是spring-jdbc的类
    <!--在spring配置文件中配置spring数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/xdz2001"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>
    <!--通过看源码知道,该类里面就是对DriverManager的封装-->
    
  3. 定义dao接口以及实现类,实现类中有数据DataSource类,为javax包下下SQL包的类
    // 定义dao接口
    public interface UserDao {
    	void save(Users users);
    	Users queryById(int id);
    	List<Users> queryAllUsers();
    }
    //定义实现类,引入DataSource属性,定义setter方法,可以通过spring注入属性值
    public class UserDaoImpl implements UserDao {
    	// 在dao实现类中引入javax包下的DataSource
    	private DataSource source;
    	// 定义setter方法,通过spring注入值,就是数据源
    	public void setSource(DataSource source) {
        	this.source = source;
    	}
    	@Override
    	public void save(Users users) {
        	try {
            	// 利用DataSource获取数据库连接
            	Connection connection = source.getConnection();
            	// SQL语句定义
            	String sql = "insert into users (name,pass,age,sex) values (?,?,?,?)";
            	// 预加载SQL语句,得到preparedStatement对象
            	PreparedStatement statement = connection.prepareStatement(sql);
            	// 占位符赋值
            	statement.setString(1,users.getName());
            	statement.setString(2,users.getPass());
            	statement.setInt(3,users.getAge());
            	statement.setString(4,users.getSex());
            	// 执行SQL语句
            	int row = statement.executeUpdate();
        	} catch (SQLException throwables) {
            	throwables.printStackTrace();
        	} finally {
        		// 关闭资源
        	}
    	}
    }
    
  4. 在Spring配置文件中定义dao实现类的bean,注入属性,值引用就是数据源
        <!--定义userDao实现类bean,userDao中有DataSource属性,引入上面定义的数据源即可-->
    <bean id="userDaoImpl" class="com.iotek.dao.impl.UserDaoImpl">
        <property name="source" ref="dataSource"/>
    </bean>
    
  5. 在实现类中通过DataSource获取数据库连接,其他操作与jdbc一致

7.2 使用jdbc模板

前面我们使用了spring提供的数据源,我们只是省略了获取数据库连接部分
通过使用我们发现除了获取数据库连接,其他大部分代码与jdbc一样
但是spring给我们提供了jdbc的模板,就是JdbcTemplate

  1. 在spring配置文件中配置数据源
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/xdz2001"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>
    
  2. 创建实体类
    public class Student implements Serializable {
    	private Integer id;
    	private String name;
    	private String pass;
    
    	public Student() {
    	}
    
    	public Student(Integer id, String name, String pass) {
        	this.id = id;
        	this.name = name;
        	this.pass = pass;
    	}
    
    	public Integer getId() {
        	return id;
    	}
    
    	public void setId(Integer id) {
        	this.id = id;
    	}
    
    	public String getName() {
        	return name;
    	}
    
    	public void setName(String name) {
        	this.name = name;
    	}
    
    	public String getPass() {
        	return pass;
    	}
    
    	public void setPass(String pass) {
        	this.pass = pass;
    	}
    
    	@Override
    	public String toString() {
        	final StringBuilder sb = new StringBuilder("Student").append('[')
                .append("id=")
                .append(id)
                .append(",name=")
                .append(name)
                .append(",pass=")
                .append(pass)
                .append(']');
        	return sb.toString();
    	}
    }
    
  3. 创建dao接口
    public interface StudentDao {
    	boolean saveStudent(Student student);
    	Student findStudent(int id);
    	Student findStudent(String name,String pass);
    	Student findStudent(String name);
    	Student fendStudent(char sex);
    	List<Student> queryAll();
    }
    
  4. 创建对应dao的实现类,引入JdbcTemplate属性,提供setter方法
    public class StudentDaoImpl implements StudentDao {
    	/*引入jdbc模板*/
    	private JdbcTemplate template;
    	/*给定setter,用于注入*/
    	public void setTemplate(JdbcTemplate template) {
        	this.template = template;
    	}
    	@Override
    	public boolean saveStudent(Student student) {
        	return false;
    	}
    
    	@Override
    	public Student findStudent(int id) {
        	return null;
    	}
    }
    
  5. 在Spring中配置JdbcTemplate,注入数据源
    <!--配置jdbc的Spring模板JdbcTemplate-->
    <bean id="template" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
  6. 将JdbcTemplate注入dao实现类中
    <!--配置dao实现类bean-->
    <bean id="studentDao" class="com.iotek.dao.impl.StudentDaoImpl">
        <!--注入jdbc模板,类中引入属性和对应的setter方法-->
        <property name="template" ref="template"/>
    </bean>
    
  7. dao中使用JdbcTemplate中的方法实现增删改查
    // update方法用于增删改,与我们封装的jdbc的update方法一样。
    public class StudentDaoImpl implements StudentDao {
    	/*引入jdbc模板*/
    	private JdbcTemplate template;
    	/*给定setter,用于注入*/
    	public void setTemplate(JdbcTemplate template) {
        	this.template = template;
    	}
    	@Override
    	public boolean saveStudent(Student student) {
        	String sql = "insert into student(name,pass) values (?,?)";
        	int row = template.update(sql, student.getName(), student.getPass());
        	if (row!=0) return true;
        	return false;
    	}
    
    	@Override
    	public Student findStudent(int id) {
        	String sql = "select * from student where id = ?";
        	Student student = template.query(sql,
                	/*实际就是给占位符赋值*/
                	new PreparedStatementSetter() {
            	@Override
            	public void setValues(PreparedStatement preparedStatement) throws SQLException {
                	preparedStatement.setInt(1,id);
            	}
        	},
                	/*结果执行器,封装结果*/
                	new ResultSetExtractor<Student>() {
            	@Override
            	public Student extractData(ResultSet resultSet) throws SQLException, DataAccessException {
                	Student std = new Student();
                	while (resultSet.next()) {
                    	std.setId(resultSet.getInt("id"));
                    	std.setName(resultSet.getString("name"));
                    	std.setPass(resultSet.getString("pass"));
                	}
                	return std;
            	}
        	});
        	return student;
    	}
    	// 与上面的query类似,只是不需要我们赋值了,参数一为SQL,参数二为结果集执行器,后面是可变参数
    	@Override
    	public Student findStudent(String name, String pass) {
        	String sql = "select * from student where name = ? and pass = ?";
        	return template.query(sql,(r) -> {
            	Student std = new Student();
            	while (r.next()) {
                	std.setId(r.getInt("id"));
                	std.setName(r.getString("name"));
                	std.setPass(r.getString("pass"));
            	}
            	return std;
        	},name,pass);
    	}
    	
    	
    	@Override
    	public Student findStudent(String name) {
        	String sql = "select * from student where name = ?";
        	/**
         	* preparedstatementcreator 执行器创建器,里面可以获取连接,然后创建预编译对象
         	* preparedstatementsetter 占位符赋值,与第一种一样
         	* resultsetExtractor 结果集执行器。封装结果
         	*/
        	return template.query(new PreparedStatementCreator() {
            	@Override
            	public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
                	return connection.prepareStatement(sql);
            	}
        	}, new PreparedStatementSetter() {
            	@Override
            	public void setValues(PreparedStatement preparedStatement) throws SQLException {
                	preparedStatement.setString(1,name);
            	}
        	}, new ResultSetExtractor<Student>() {
            	@Override
            	public Student extractData(ResultSet resultSet) throws SQLException, DataAccessException {
                	Student std = new Student();
                	while (resultSet.next()) {
                    	std.setId(resultSet.getInt("id"));
                    	std.setName(resultSet.getString("name"));
                    	std.setPass(resultSet.getString("pass"));
                	}
                	return std;
            	}
        	});
    	}
    	// 查询对象最简单的一种方法
    	@Override
    	public Student fendStudent(char sex) {
        	String sql = "select * from student where sex = ?";
        	// 提前创建一个rowMap,如果使用内部类,需要自己实现接口,比较复杂
        	RowMapper<Student> rowMapper = new BeanPropertyRowMapper<>(Student.class);
        	return template.queryForObject(sql,rowMapper,sex);
    	}
    	// 查询多个对象,与上面的方法一样,第三个参数就是占位符需要的可变参数列表
    	@Override
    	public List<Student> queryAll() {
        	String sql = "select * from student";
        	RowMapper<Student> rowMapper = new BeanPropertyRowMapper<>(Student.class);
        	return template.query(sql,rowMapper);
    	}
    }
    

8、 Spring对web层支持对应后面整合web

8.1 创建实体类和对应dao接口及实现类

public class Users {
    private Integer id;
    private String name;
    private String pass;
    private int age;
    private String sex;

    public Users() {
    }

    public Users(String name, String pass, int age, String sex) {
        this.name = name;
        this.pass = pass;
        this.age = age;
        this.sex = sex;
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getPass() {
        return pass;
    }

    public void setPass(String pass) {
        this.pass = pass;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Users").append('[')
                .append("id=")
                .append(id)
                .append(",name=")
                .append(name)
                .append(",pass=")
                .append(pass)
                .append(",age=")
                .append(age)
                .append(",sex=")
                .append(sex)
                .append(']');
        return sb.toString();
    }
}
public interface UsersDao {
    boolean save(Users users);
    Users queryByNamePass(String name,String pass);
    Users queryById(int id);
    List<Users> queryAll();
}
public class UsersDaoImpl implements UsersDao {
    private JdbcTemplate template;

    public void setTemplate(JdbcTemplate template) {
        this.template = template;
    }

    @Override
    public boolean save(Users users) {
        return false;
    }

    @Override
    public Users queryByNamePass(String name, String pass) {
        Users users = null;
        try {
            users = template.queryForObject(
                    "select * from users where name = ? and pass = ?",
                    new BeanPropertyRowMapper<>(Users.class),
                    name,pass
            );
        } catch (DataAccessException e) {
            e.printStackTrace();
        }
        return users;
    }

    @Override
    public Users queryById(int id) {
        return null;
    }

    @Override
    public List<Users> queryAll() {
        return null;
    }
}

8.2 创建service接口和实现类

public interface UsersService {
    Users login(String name,String pass);
    boolean regist(Users users);
}
public class UsersServiceImpl implements UsersService {
    private UsersDao usersDao;

    public void setUsersDao(UsersDao usersDao) {
        this.usersDao = usersDao;
    }

    @Override
    public Users login(String name, String pass) {
        if (name == null) {
            return null;
        }
        if (pass == null) {
            return null;
        }
        return usersDao.queryByNamePass(name,pass);
    }

    @Override
    public boolean regist(Users users) {
        return false;
    }
}

8.3 创建servlet,并在初始化方法中获取加载配置

@WebServlet(name = "UsersServlet",urlPatterns = "/usersServlet")
public class UsersServlet extends HttpServlet {
    private UsersService usersService;
    ApplicationContext applicationContext;
    @Override
    public void init() throws ServletException {
        applicationContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        usersService = applicationContext.getBean(UsersService.class);
        Users users = usersService.login(request.getParameter("name"), request.getParameter("password"));
        if (users != null) {
            request.getRequestDispatcher("index.jsp").forward(request,response);
        }
        response.getWriter().write("你好");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request,response);
    }
}

8.4 ApplicationContext配置

<?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 https://www.springframework.org/schema/context/spring-context.xsd">
	<!--引入db.properties文件-->
    <context:property-placeholder location="classpath:db.properties"/>
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.urlj}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    <bean id="template" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <bean id="userDao" class="com.iotek.dao.impl.UsersDaoImpl">
        <property name="template" ref="template"/>
    </bean>
    <bean id="userService" class="com.iotek.service.impl.UsersServiceImpl">
        <property name="usersDao" ref="userDao"/>
    </bean>
</beans>

8.5 web.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <display-name>Archetype Created Web Application</display-name>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    <!--配置上下文参数,加载配置文件-->
    <context-param>
        <param-name>applicationContext</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <!--配置上下文加载的监听-->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

8.6 页面部分

<html>
<head>
    <base href="<%=basePath%>"/>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
<div style="margin: 20px auto;">
    <fieldset>
        <legend>欢迎登录</legend>
        <form action="usersServlet" method="post">
            姓名:<input type="text"><br>
            密码:<input type="password"><br>
            <input type="hidden" name="method" value="login">
            <input type="submit" value="登录">
        </form>
    </fieldset>
</div>
</body>
</html>

9、 装配Bean 基于注解

  • 注解:就是一个类,使用@注解名称
  • 开发中:使用注解 取代 xml配置文件。

9.1 注解

@Component取代<bean class=“”>:默认bean的名字是类名首字母小写
@Component(“id”) 取代 <bean id=“” class=“”>:可以写为@Component(value=“id”)

9.2web开发,提供3个@Component注解衍生注解(功能一样)取代<bean class=“”>

@Repository :dao层
@Service:service层
@Controller:web层

9.3依赖注入,给私有字段设置,也可以给setter方法设置

使用注解注入的方式,属性可以不写setter方法

普通值:@Value("")
引用值:
	方式1:按照【类型】注入
		@Autowired
	方式2:按照【名称】注入1
		@Autowired
		@Qualifier("名称"),可以写为@Qualifier(value="名称")
	方式3:按照【名称|类型】注入2
		@Resource:按照类型匹配
		@Resource("xxx"):按照后面给定的名称匹配,可以写为@Resource(name="xxx")

@Nullable:这个注解一般是放方法参数上,表示此属性允许为空。
@Autowired(required=“false”):此注解中的required属性默认为true,如果显示的什么为false,表示此注入的值可以为空。

9.4生命周期

初始化:@PostConstruct
销毁:@PreDestroy

9.5作用域

@Scope("prototype") 多例
  • 注解使用前提,添加命名空间,让spring扫描含有注解类
  • schema命名空间:
    1. 命名空间声明:
    默认:xmlns=“” <标签名> --> <bean>
    显示:xmlns:别名=“” <别名:标签名> --> <context:…>
    2. 确定schema xsd 文件位置
    xsl:schemaLocation=“名称 位置 名称2 位置2 …”
    内容都是成对了【名称 位置】
    下面代码片段中3,6,7行与之对应就是添加命名空间
<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.itheima.g_annotation.a_ioc,com.iotek.servce"></context:component-scan>
</beans>

10、纯java配置方式

在springboot中完全舍弃配置文件,而采用纯java的配置方式

  • 实体类
//这里这个注解的意思,就是说明这个类被spring接管了,注册到了容器中
@Component
publie class User{
	private String name;
	public String getName(){
		return name;
	}
	@Value("fds")//属性注入值
	public void setName(String name){
		this.name = name;
	}
}
  • 配置文件
//这个也会spring容器托管,注册到容器,因为他本来就是一个@Component
//@Configuration代表这是一个配置类,就是我们之前看到的applicationContext.xml
@Configuration
@ComponentScan("com.iotek")
@Import(ConfigTest2.class)
public class ConfigTest{
	//注册一个bean,就相当于我们之前写的一个bean标签
	//这个方法的名字,就相当于bean标签中的id属性
	//这个方法的返回值,就相当于bean标签中的class属性
	@Bean
	public User user(){
		return new User();//就是返回要注入到bean的对象!
	}
}

  • 测试类
public class MyTest{
	public static void main(String[]args){
		//如果完全使用了配置类的方式,我们就只能通过AnnotationConfig上下文来获取容器,通过配置类的class对象加载
		ApplicationContext context = new AnnotationConfigApplicationContext(ConfigTest.class);
		User user = (User) context.getBean("user");
		System.out.println(user);
	}
}
  • 这种纯java的配置方式,在springboot中非常常见。

11、 要求

先练习:xml
IoC
DI
xml配置
实例化方式
作用域
生命周期
属性注入:构造方法、setter、、集合
再练习:注解
web开发
(p命名空间、SpEL)

1、spring day01回顾

1.1 编写流程(基于xml)

  1. 导入jar包:4+1 --> beans/core/context/expression | commons-logging
  2. 编写目标类:dao和service
  3. spring配置文件
    IoC:<bean id=“” class=“” >
    DI:<bean> <property name=“” value=“” | ref=“”>
  • 实例化方式:
  1. 默认构造:<bean id=“” class=“” >
  2. 静态工厂:<bean id=“” class=“工厂类” factory-method=“静态方法”>
  3. 实例工厂:<bean id=“工厂id” class=“工厂类”> <bean id=“” factory-bean=“工厂id” factory-method=“方法”>
  • 作用域:<bean id=“” class=“” scope=“singleton | prototype”>
  • 生命周期:<bean id=“” class=“” init-method=“” destroy-method=“”>
    后处理bean BeanPostProcessor接口,<bean class=“注册”> ,对容器中所有的bean都生效
  • 属性注入
    1. 构造方法注入:<bean>
    2. setter方法注入:<bean>
    3. p命名空间:简化<property> <bean p:属性名=“普通值” p:属性名-ref=“引用值”> 注意声明命名空间
    4. SpEL:<property name=“” value=“#{表达式}”>
      #{123} #{‘abc’}
      #{beanId.propName?.methodName()}
      #{T(类).静态方法|字段}
    5. 集合
    • 数组<array>
    • List <list>
    • Set <set>
    • Map <map>
    • Properties <props>…
    1. 核心api
      BeanFactory,延迟实例化bean,第一次调用getBean
      ApplicationContext 一般常用,功能更强
      ClassPathXmlApplicationContext 加载classpath xml文件
      FileSystemXmlApplicationContext 加载指定盘符文件 , ServletContext.getRealPath()

1.2 后处理bean 对一个生效

@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if("userServiceId".equals(beanName)){
			System.out.println("前方法 : " + beanName);
		}
		return bean;
	}

1.3 注解

  1. 扫描含有注解的类
    <context:component-scan base-package=“…”>
  2. 常见的注解
    @Component 组件,任意bean
    WEB
    @Controller web层
    @Service service层
    @Repository dao层
    注入 --> 字段或setter方法
    普通值:@Value
    引用值:
    类型:@Autowired
    名称1:@Autowired @Qualifier(“名称”)
    名称2:@Resource(“名称”)
    作用域:@Scope(“prototype”)
    生命周期:
    初始化:@PostConstruct
    销毁方法:@PreDestroy

1.4 注解和xml混合使用

  1. 将所有的bean都配置xml中
    <bean id=“” class=“”>
  2. 将所有的依赖都使用注解
    @Autowired
    默认不生效。为了生效,需要在xml配置:context:annotation-config
  • 总结
    注解1:<context:component-scan base-package=" ">
    注解2:<context:annotation-config>
    1.一般情况两个注解不一起使用。
    2.“注解1”扫描含有注解(@Component 等)类,注入注解自动生效。
    “注解2”只在xml和注解(注入)混合使用时,使注入注解生效。

2、AOP

2.1 AOP介绍

2.1.1 什么是AOP
  • 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
  • AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
  • 经典应用:事务管理、性能监视、安全检查、缓存 、日志等
  • Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码
  • AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入
  • 将关注点代码(重复性代码或者额外增强功能的代码)和业务逻辑分离开
2.1.2 为什么需要AOP

在这里插入图片描述

  • 上面展示的就是传统的javaSE的做法。
  • 上面的增强方式就是纵向继承的方式
  • 此时如果我们需求变化,如Test01校验不需要,但Test02的需要,那么显然我们需要修改Test01的代码,去掉继承和里面方法的调用
  • 而对于前面的问题。需要修改代码,不利于后期的维护
2.1.3 AOP实现原理
  1. aop底层将采用代理机制进行实现。
  2. 对于需要增强的类生成代理类,创建代理对象
  3. 在代理类中除了目标类方法执行外,加入增强的代码
  4. 最终生成代理对象进行调用。而如果不需要增强的话:
  5. 可以修改代理类,因为代理类我们可以随时创建
  6. 或者将调用的代理类替换原来的目标类即可
  7. 接口 + 实现类:spring采用 jdk 的动态代理Proxy。
  8. 实现类:spring 采用 cglib字节码增强。
2.1.4 AOP术语【掌握】
  1. target目标类:需要被代理的类。例如:UserService
  2. Joinpoint连接点:所谓连接点是指那些可能被拦截到的方法。例如:所有的方法
  3. PointCut切入点:已经被增强的连接点。例如:addUser()
  4. advice通知/增强,增强代码。例如:after、before
  5. Weaving织入:是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程.
  6. proxy代理类
  7. Aspect切面:是切入点pointcut和通知advice的结合
    一个线是一个特殊的面。
    一个切入点和一个通知,组成成一个特殊的面。
    AOP

2.2 手动方式

2.2.1 JDK动态代理
  • JDK动态代理 对“装饰者”设计模式 简化。使用前提:必须有接口
  1. 目标类:接口 + 实现类
  2. 切面类:用于存通知 MyAspect
  3. 工厂类:编写工厂生成代理
  4. 测试
2.2.1.1 目标类
public interface UserService {
	
	public void addUser();
	public void updateUser();
	public void deleteUser();
}
2.2.1.2 切面类
public class MyAspect {
	
	public void before(){
		System.out.println("鸡首");
	}
	
	public void after(){
		System.out.println("牛后");
	}
}
2.2.1.3 工厂
public class MyBeanFactory {
	
	public static UserService createService(){
		//1 目标类
		final UserService userService = new UserServiceImpl();
		//2切面类
		final MyAspect myAspect = new MyAspect();
		/* 3 代理类:将目标类(切入点)和 切面类(通知) 结合 --> 切面
		 * 	Proxy.newProxyInstance
		 * 		参数1:loader ,类加载器,动态代理类 运行时创建,任何类都需要类加载器将其加载到内存。
		 * 			一般情况:当前类.class.getClassLoader();
		 * 					目标类实例.getClass().get...
		 * 		参数2:Class[] interfaces 代理类需要实现的所有接口
		 * 			方式1:目标类实例.getClass().getInterfaces()  ;注意:只能获得自己接口,不能获得父元素接口
		 * 			方式2:new Class[]{UserService.class}   
		 * 			例如:jdbc 驱动  --> DriverManager  获得接口 Connection
		 * 		参数3:InvocationHandler  处理类,接口,必须进行实现类,一般采用匿名内部
		 * 			提供 invoke 方法,代理类的每一个方法执行时,都将调用一次invoke
		 * 				参数31:Object proxy :代理对象
		 * 				参数32:Method method : 代理对象当前执行的方法的描述对象(反射)
		 * 					执行方法名:method.getName()
		 * 					执行方法:method.invoke(对象,实际参数)
		 * 				参数33:Object[] args :方法实际参数
		 * 
		 */
		UserService proxService = (UserService)Proxy.newProxyInstance(
								MyBeanFactory.class.getClassLoader(), 
								userService.getClass().getInterfaces(), 
								new InvocationHandler() {
									
									@Override
									public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
										
										//前执行
										myAspect.before();
										
										//执行目标类的方法
										Object obj = method.invoke(userService, args);
										
										//后执行
										myAspect.after();
										
										return obj;
									}
								});
		return proxService;
	}
}
2.2.1.4 测试
@Test
public void demo01(){
	UserService userService = MyBeanFactory.createService();
	userService.addUser();
	userService.updateUser();
	userService.deleteUser();
}
2.2.2 CGLIB字节码增强
  • 没有接口,只有实现类。很多时候有些类知识单独的类,没有实现接口,这个时候就不能使用静态代理或者jdk代理,就需要使用cglib代理
  • cglib可以认为就是一个高性能的代码生成包,底层是一个ASM的字节码框架
  • 采用字节码增强框架cglib,在运行时创建目标类的子类,从而对目标类进行增强。
  • 导入jar包:
    自己导包(了解):
    核心:hibernate-distribution-3.6.10.Final\lib\bytecode\cglib\cglib-2.2.jar
    依赖:struts-2.3.15.3\apps\struts2-blank\WEB-INF\lib\asm-3.3.jar
    spring-core…jar 已经整合以上两个内容
  • 主要:给目标类生成子类,要求目标类不能被final修饰,目标对象的方法不能是final或者static修饰的。因为不能被拦截。
2.2.2.1 工厂类
public class MyBeanFactory {
	public static UserServiceImpl createService(){
		//1 目标类
		final UserServiceImpl userService = new UserServiceImpl();
		//2切面类
		final MyAspect myAspect = new MyAspect();
		// 3.代理类 ,采用cglib,底层创建目标类的子类
		//3.1 核心类
		Enhancer enhancer = new Enhancer();
		//3.2 确定父类
		enhancer.setSuperclass(userService.getClass());

		/* 3.3 设置回调函数 , MethodInterceptor接口 等效 jdk InvocationHandler接口
		 * 	intercept() 等效 jdk  invoke()
		 * 		参数1、参数2、参数3:以invoke一样
		 * 		参数4:methodProxy 方法的代理
		 */
		enhancer.setCallback(new MethodInterceptor(){

			@Override
			public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
				
				//前
				myAspect.before();
				
				//执行目标类的方法
				Object obj = method.invoke(userService, args);
				// * 执行代理类的父类 ,执行目标类 (目标类和代理类 父子关系)
				methodProxy.invokeSuper(proxy, args);
				
				//后
				myAspect.after();
				
				return obj;
			}
		});
		//3.4 创建代理
		UserServiceImpl proxService = (UserServiceImpl) enhancer.create();
		
		return proxService;
	}
}

2.3 AOP联盟通知类型

  • AOP联盟为通知Advice定义了org.aopalliance.aop.Advice

  • Spring按照通知Advice在目标类方法的连接点位置,可以分为5类
    • 前置通知 org.springframework.aop.MethodBeforeAdvice
    在目标方法执行前实施增强
    • 后置通知 org.springframework.aop.AfterReturningAdvice
    在目标方法执行后实施增强
    • 环绕通知 org.aopalliance.intercept.MethodInterceptor
    在目标方法执行前后实施增强
    • 异常抛出通知 org.springframework.aop.ThrowsAdvice
    在方法抛出异常后实施增强
    • 引介通知 org.springframework.aop.IntroductionInterceptor
    在目标类中添加一些新的方法和属性

  • 环绕通知,必须手动执行目标方法

try{
   //前置通知
   //执行目标方法
   //后置通知
} catch(){
   //抛出异常通知
}

2.4 spring编写代理:半自动

  • 让spring 创建代理对象,从spring容器中手动的获取代理对象。
  • 导入jar包:
    核心:4+1
    AOP:AOP联盟(规范)、spring-aop (实现)
    jar包
2.4.1 目标类
public interface UserService {
	
	public void addUser();
	public void updateUser();
	public void deleteUser();
}
2.4.2 切面类
/**
 * 切面类中确定通知,需要实现不同接口,接口就是规范,从而就确定方法名称。
 * * 采用“环绕通知” MethodInterceptor
 */
public class MyAspect implements MethodInterceptor {

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		
		System.out.println("前3");
		
		//手动执行目标方法
		Object obj = mi.proceed();
		
		System.out.println("后3");
		return obj;
	}
}
2.4.3 spring配置
	<!-- 1 创建目标类 -->
	<bean id="userServiceId" class="com.itheima.b_factory_bean.UserServiceImpl"></bean>
	<!-- 2 创建切面类 -->
	<bean id="myAspectId" class="com.itheima.b_factory_bean.MyAspect"></bean>

	<!-- 3 创建代理类 
		* 使用工厂bean FactoryBean ,底层调用 getObject() 返回特殊bean
		* ProxyFactoryBean 用于创建代理工厂bean,生成特殊代理对象
			interfaces : 确定接口们
				通过<array>可以设置多个值
				只有一个值时,value=""
			target : 确定目标类
			interceptorNames : 通知 切面类的名称,类型String[],如果设置一个值 value=""
			optimize :强制使用cglib
				<property name="optimize" value="true"></property>
		底层机制
			如果目标类有接口,采用jdk动态代理
			如果没有接口,采用cglib 字节码增强
			如果声明 optimize = true ,无论是否有接口,都采用cglib
	-->
	<bean id="proxyServiceId" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="interfaces" value="com.itheima.b_factory_bean.UserService"></property>
		<property name="target" ref="userServiceId"></property>
		<property name="interceptorNames" value="myAspectId"></property>
	</bean>
2.4.4 测试
   @Test
   public void demo01(){
   	String xmlPath = "com/itheima/b_factory_bean/beans.xml";
   	ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
   	
   	//获得代理类
   	UserService userService = (UserService) applicationContext.getBean("proxyServiceId");
   	userService.addUser();
   	userService.updateUser();
   	userService.deleteUser();
   }

2.5 spring aop编程:全自动【掌握】

  • 从spring容器获得目标类,如果配置aop,spring将自动生成代理。
  • 要确定目标类,aspectj 切入点表达式,导入jar包
    spring-framework-3.0.2.RELEASE-dependencies\org.aspectj\com.springsource.org.aspectj.weaver\1.6.8.RELEASE
2.5.1 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: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">
	<!-- 1 创建目标类 -->
	<bean id="userServiceId" class="com.itheima.c_spring_aop.UserServiceImpl"></bean>
	<!-- 2 创建切面类(通知) -->
	<bean id="myAspectId" class="com.itheima.c_spring_aop.MyAspect"></bean>
	<!-- 3 aop编程 
		3.1 导入命名空间
		3.2 使用 <aop:config>进行配置
				proxy-target-class="true" 声明时使用cglib代理
			<aop:pointcut> 切入点 ,从目标对象获得具体方法
			<aop:advisor> 特殊的切面,只有一个通知 和 一个切入点
				advice-ref 通知引用
				pointcut-ref 切入点引用
		3.3 切入点表达式
			execution(* com.itheima.c_spring_aop.*.*(..))
			选择方法         返回值任意   包             类名任意   方法名任意   参数任意
	-->
	<aop:config proxy-target-class="true">
		<aop:pointcut expression="execution(* com.itheima.c_spring_aop.*.*(..))" id="myPointCut"/>
		<aop:advisor advice-ref="myAspectId" pointcut-ref="myPointCut"/>
	</aop:config>
</beans>
2.5.2 测试
	@Test
	public void demo01(){
		String xmlPath = "com/itheima/c_spring_aop/beans.xml";
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
		
		//获得目标类
		UserService userService = (UserService) applicationContext.getBean("userServiceId");
		userService.addUser();
		userService.updateUser();
		userService.deleteUser();
	}

3 AspectJ

3.1 介绍

  • AspectJ是一个基于Java语言的AOP框架
  • spring自己开发的AOP过于繁琐。已经弃用了,使用AOP联盟开发的AspectJ框架
  • Spring2.0以后新增了对AspectJ切点表达式支持
  • @AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面
    新版本Spring框架,建议使用AspectJ方式来开发AOP,基于AspectJ开发
  • 主要用途:自定义开发

3.2 切入点表达式【掌握】

  1. execution() 用于描述方法 【掌握】
	语法:execution(修饰符  返回值  包.类.方法名(参数) throws异常)
		修饰符,一般省略
			public		公共方法
			*			任意
		返回值,不能省略
			void			返回没有值
			String		返回值字符串
			* 			任意
		包,[省略]
			com.itheima.crm			固定包
			com.itheima.crm.*.service	crm包下面子包任意 (例如:com.itheima.crm.staff.service)
			com.itheima.crm..			crm包下面的所有子包(含自己)
			com.itheima.crm.*.service..	crm包下面任意子包,固定目录service,service目录任意包
		类,[省略]
			UserServiceImpl			指定类
			*Impl					以Impl结尾
			User*					以User开头
			User+					User类及其子类
			*						任意
		方法名,不能省略
			addUser					固定方法
			add*						以add开头
			*Do						以Do结尾
			*						任意
		(参数)
			()						无参
			(int)						一个整型
			(int ,int)					两个
			(..)						参数任意
		throws ,可省略,一般不写。

 综合1
	execution(* com.itheima.crm.*.service..*.*(..))
 综合2
	<aop:pointcut expression="execution(* com.itheima.*WithCommit.*(..)) || 
                          execution(* com.itheima.*Service.*(..))" id="myPointCut"/>
  1. within:匹配包或子包中的方法(了解)
    within(com.itheima.aop…*)
  2. this:匹配实现接口的代理对象中的方法(了解)
    this(com.itheima.aop.user.UserDAO)
  3. target:匹配实现接口的目标对象中的方法(了解)
    target(com.itheima.aop.user.UserDAO)
  4. args:匹配参数格式符合标准的方法(了解)
    args(int,int)
  5. bean(id) 对指定的bean所有的方法(了解)
    bean(‘userServiceId’)

3.3 AspectJ 通知类型

  • aop联盟定义通知类型,具有特性接口,必须实现,从而确定方法名称。
  • aspectj 通知类型,只定义类型名称。以及方法格式。
  • 个数:6种,知道5种,掌握1中。
    before:前置通知(应用:各种校验)
    在方法执行前执行,如果通知抛出异常,阻止方法运行
    afterReturning:后置通知(应用:常规数据处理)
    方法正常返回后执行,如果方法中抛出异常,通知无法执行
    必须在方法执行后才执行,所以可以获得方法的返回值。
    around:环绕通知(应用:十分强大,可以做任何事情)
    方法执行前后分别执行,可以阻止方法的执行
    必须手动执行目标方法
    afterThrowing:抛出异常通知(应用:包装异常信息)
    方法抛出异常后执行,如果方法没有抛出异常,无法执行
    after:最终通知(应用:清理现场)
    方法执行完毕后执行,无论方法中是否出现异常
    环绕

try{
//前置:before
//手动执行目标方法
//后置:afterRetruning
} catch(){
//抛出异常 afterThrowing
} finally{
//最终 after
}

3.4 导入jar包

  • 4个:
    aop联盟规范
    spring aop 实现
    aspect 规范
    spring aspect 实现

3.5 基于xml

  1. 目标类:接口 + 实现
  2. 切面类:编写多个通知,采用aspectj 通知名称任意(方法名任意)
  3. aop编程,将通知应用到目标类
  4. 测试
3.5.1 切面类
/**
 * 切面类,含有多个通知
 */
public class MyAspect {
	
	public void myBefore(JoinPoint joinPoint){
		System.out.println("前置通知 : " + joinPoint.getSignature().getName());
	}
	
	public void myAfterReturning(JoinPoint joinPoint,Object ret){
		System.out.println("后置通知 : " + joinPoint.getSignature().getName() + " , -->" + ret);
	}
	
	public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
		System.out.println("前");
		//手动执行目标方法
		Object obj = joinPoint.proceed();
		
		System.out.println("后");
		return obj;
	}
	
	public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
		System.out.println("抛出异常通知 : " + e.getMessage());
	}
	
	public void myAfter(JoinPoint joinPoint){
		System.out.println("最终通知");
	}

}
3.5.2 spring配置
<!-- 1 创建目标类 -->
	<bean id="userServiceId" class="com.itheima.d_aspect.a_xml.UserServiceImpl"></bean>
	<!-- 2 创建切面类(通知) -->
	<bean id="myAspectId" class="com.itheima.d_aspect.a_xml.MyAspect"></bean>
	<!-- 3 aop编程 
		<aop:aspect> 将切面类 声明“切面”,从而获得通知(方法)
			ref 切面类引用
		<aop:pointcut> 声明一个切入点,所有的通知都可以使用。
			expression 切入点表达式
			id 名称,用于其它通知引用
	-->
	<aop:config>
		<aop:aspect ref="myAspectId">
			<!--**
			切入点的配置可以放在aspect外面,config里面
			表示先配置切入点,然后配置切面,在切面里面配置通知,跟切点关联形成切面
			也可以像现在这样放在里面,表示直接配置切面:
			切面是由切点和通过组成的。所以需要在切面里面配置切点和通知,进行关联
			**-->
			<aop:pointcut expression="execution(* com.itheima.d_aspect.a_xml.UserServiceImpl.*(..))" id="myPointCut"/>
			
			<!-- 3.1 前置通知 
				<aop:before method="" pointcut="" pointcut-ref=""/>
					method : 通知,及方法名
					pointcut :切入点表达式,此表达式只能当前通知使用。
					pointcut-ref : 切入点引用,可以与其他通知共享切入点。
				通知方法格式:public void myBefore(JoinPoint joinPoint){
					参数1:org.aspectj.lang.JoinPoint  用于描述连接点(目标方法),获得目标方法名等
				例如:
			<aop:before method="myBefore" pointcut-ref="myPointCut"/>
			-->
			
			<!-- 3.2后置通知  ,目标方法后执行,获得返回值
				<aop:after-returning method="" pointcut-ref="" returning=""/>
					returning 通知方法第二个参数的名称
				通知方法格式:public void myAfterReturning(JoinPoint joinPoint,Object ret){
					参数1:连接点描述
					参数2:类型Object,参数名 returning="ret" 配置的
				例如:
			<aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="ret" />
			-->
			
			<!-- 3.3 环绕通知 
				<aop:around method="" pointcut-ref=""/>
				通知方法格式:public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
					返回值类型:Object
					方法名:任意
					参数:org.aspectj.lang.ProceedingJoinPoint
					抛出异常
				执行目标方法:Object obj = joinPoint.proceed();
				例如:
			<aop:around method="myAround" pointcut-ref="myPointCut"/>
			-->
			<!-- 3.4 抛出异常
				<aop:after-throwing method="" pointcut-ref="" throwing=""/>
					throwing :通知方法的第二个参数名称
				通知方法格式:public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
					参数1:连接点描述对象
					参数2:获得异常信息,类型Throwable ,参数名由throwing="e" 配置
				例如:
			<aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e"/>
			-->
			<!-- 3.5 最终通知 -->			
			<aop:after method="myAfter" pointcut-ref="myPointCut"/>
			
		</aop:aspect>
	</aop:config>

3.6 注意

通过上面2.5和3.5对比我们发现
在配置aop时。有两种常用的配置

  • 配置方式一:使用advisor,2.5的方式
    <!-- 1 创建目标类 -->
    <bean id="userServiceId" class="com.itheima.c_spring_aop.UserServiceImpl"/>
    <!-- 2 创建切面类(通知) -->
    <bean id="myAspectId" class="com.itheima.c_spring_aop.MyAspect"/>
    <!-- 3 配置aop-->
    <aop:config proxy-target-class="true">
    	<!--配置切点-->
    	<aop:pointcut expression="execution(* com.itheima.c_spring_aop.*.*(..))" id="myPointCut"/>
    	<!--配置通知器,前面的通知因为实现了接口,就是一个通知器了,不需要指定方法-->
    	<aop:advisor advice-ref="myAspectId" pointcut-ref="myPointCut"/>
    </aop:config>
    
  • 配置方式二:使用aspect,3.5的方式
    <!-- 1 创建目标类 -->
    <bean id="userServiceId" class="com.itheima.d_aspect.a_xml.UserServiceImpl"/>
    <!-- 2 创建切面类(通知) -->
    <bean id="myAspectId" class="com.itheima.d_aspect.a_xml.MyAspect"/>
    <!-- 3 配置aop -->
    <aop:config>
    	<!--配置切点-->
    	<aop:pointcut expression="execution(* com.itheima.c_spring_aop.*.*(..))" id="myPointCut"/>
    	<!--配置切面-->
    	<aop:aspect ref="myAspectId">
    		< !-- 配置通知类型 -->
    		<aop:after method="myAfter" pointcut-ref="myPointCut"/>
    	</aop:aspect>
    </aop:config>
    
  • 上面两种配置方式的区别如下

<aop:aspect>:定义切面(切面包含通知和切入点)
<aop:advisor>:定义通知器(也包含通知和切入点)
实现方式不同(通知不同)

<aop:aspect>定义切面时,通知类只需要一般的bean;
<aop:advisor>中引用通知时,通知必须实现对应的advice接口

使用场景不同

<aop:aspect>:大多用于日志和缓存
<aop:advisor>:大多用于事物管理

两者都是将通知和切入点进行了封装,原理基本上是一样的。

3.7 基于注解

3.7.1 替换bean
<!-- 1 创建目标类 -->
	<bean id="userServiceId" class="com.itheima.d_aspect.b_anno.UserServiceImpl"></bean>
	<!-- 2 创建切面类(通知) -->
	<bean id="myAspectId" class="com.itheima.d_aspect.b_anno.MyAspect"></bean>
  
注意:扫描

<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/aop 
       					   http://www.springframework.org/schema/aop/spring-aop.xsd
       					   http://www.springframework.org/schema/context 
       					   http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 1.扫描 注解类 -->
	<context:component-scan base-package="com.itheima.d_aspect.b_anno"></context:component-scan>
3.7.2 替换aop
  • 必须进行aspectj 自动代理
<!-- 2.确定 aop注解生效 -->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  • 声明切面
 <aop:aspect ref="myAspectId">
  • 替换前置通知
<aop:before method="myBefore" pointcut="execution(* com.itheima.d_aspect.b_anno.UserServiceImpl.*(..))"/>
	//切入点当前有效
	@Before("execution(* com.itheima.d_aspect.b_anno.UserServiceImpl.*(..))")
	public void myBefore(JoinPoint joinPoint){
		System.out.println("前置通知 : " + joinPoint.getSignature().getName());
	}
  • 替换 公共切入点
<aop:pointcut expression="execution(* com.itheima.d_aspect.b_anno.UserServiceImpl.*(..))" id="myPointCut"/>
//声明公共切入点
	@Pointcut("execution(* com.itheima.d_aspect.b_anno.UserServiceImpl.*(..))")
	private void myPointCut(){
	}
  • 替换后置
<aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="ret" />
	@AfterReturning(value="myPointCut()" ,returning="ret")
	public void myAfterReturning(JoinPoint joinPoint,Object ret){
		System.out.println("后置通知 : " + joinPoint.getSignature().getName() + " , -->" + ret);
	}
  • 替换环绕
<aop:around method="myAround" pointcut-ref="myPointCut"/>
@Around(value = "myPointCut()")
	public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
		System.out.println("前");
		//手动执行目标方法
		Object obj = joinPoint.proceed();
		
		System.out.println("后");
		return obj;
	}
  • 替换抛出异常
<aop:after-throwing method="myAfterThrowing" pointcut="execution(* com.itheima.d_aspect.b_anno.UserServiceImpl.*(..))" throwing="e"/>
@AfterThrowing(value="execution(* com.itheima.d_aspect.b_anno.UserServiceImpl.*(..))" ,throwing="e")
	public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
		System.out.println("抛出异常通知 : " + e.getMessage());
	}
3.7.3 切面类
/**
 * 切面类,含有多个通知
 */
@Component
@Aspect
public class MyAspect {
	
	//切入点当前有效
//	@Before("execution(* com.itheima.d_aspect.b_anno.UserServiceImpl.*(..))")
	public void myBefore(JoinPoint joinPoint){
		System.out.println("前置通知 : " + joinPoint.getSignature().getName());
	}
	
	//声明公共切入点
	@Pointcut("execution(* com.itheima.d_aspect.b_anno.UserServiceImpl.*(..))")
	private void myPointCut(){
	}
	
//	@AfterReturning(value="myPointCut()" ,returning="ret")
	public void myAfterReturning(JoinPoint joinPoint,Object ret){
		System.out.println("后置通知 : " + joinPoint.getSignature().getName() + " , -->" + ret);
	}
	
//	@Around(value = "myPointCut()")
	public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
		System.out.println("前");
		//手动执行目标方法
		Object obj = joinPoint.proceed();
		
		System.out.println("后");
		return obj;
	}
	
//	@AfterThrowing(value="execution(* com.itheima.d_aspect.b_anno.UserServiceImpl.*(..))" ,throwing="e")
	public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
		System.out.println("抛出异常通知 : " + e.getMessage());
	}
	
	@After("myPointCut()")
	public void myAfter(JoinPoint joinPoint){
		System.out.println("最终通知");
	}

}
3.7.4 spring配置
<!-- 1.扫描 注解类 -->
	<context:component-scan base-package="com.itheima.d_aspect.b_anno"></context:component-scan>
	
	<!-- 2.确定 aop注解生效 -->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
3.7.5 aop注解总结

@Aspect 声明切面,修饰切面类,从而获得 通知。
通知
@Before 前置
@AfterReturning 后置
@Around 环绕
@AfterThrowing 抛出异常
@After 最终
切入点
@PointCut ,修饰方法 private void xxx(){} 之后通过“方法名”获得切入点引用

4 JdbcTemplate

  • spring 提供用于操作JDBC工具类,类似:DBUtils。
  • 依赖 连接池DataSource (数据源)

4.1 环境搭建

4.1.1 创建表
create database ee19_spring_day02;
use ee19_spring_day02;
create table t_user(
  id int primary key auto_increment,
  username varchar(50),
  password varchar(32)
);

insert into t_user(username,password) values('jack','1234');
insert into t_user(username,password) values('rose','5678');
4.1.2 导入jar包

在这里插入图片描述

4.1.3 javabean
package com.itheima.domain;

public class User {
	
	private Integer id;
	private String username;
	private String password;

4.2 使用api(了解)

public static void main(String[] args) {
		
		//1 创建数据源(连接池) dbcp
		BasicDataSource dataSource = new BasicDataSource();
		// * 基本4项
		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
		dataSource.setUrl("jdbc:mysql://localhost:3306/ee19_spring_day02");
		dataSource.setUsername("root");
		dataSource.setPassword("1234");
		
		
		//2  创建模板
		JdbcTemplate jdbcTemplate = new JdbcTemplate();
		jdbcTemplate.setDataSource(dataSource);
		
		
		//3 通过api操作
		jdbcTemplate.update("insert into t_user(username,password) values(?,?);", "tom","998");
		
	}

4.3 配置DBCP

<!-- 创建数据源 -->
	<bean id="dataSourceId" class="org.apache.commons.dbcp.BasicDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
		<property name="url" value="jdbc:mysql://localhost:3306/ee19_spring_day02"></property>
		<property name="username" value="root"></property>
		<property name="password" value="1234"></property>
	</bean>
	<!-- 创建模板 ,需要注入数据源-->
	<bean id="jdbcTemplateId" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSourceId"></property>
	</bean>
	
	<!-- 配置dao -->
	<bean id="userDaoId" class="com.itheima.c_dbcp.UserDao">
		<property name="jdbcTemplate" ref="jdbcTemplateId"></property>
	</bean>

4.4 配置C3P0

<!-- 创建数据源 c3p0-->
	<bean id="dataSourceId" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/ee19_spring_day02"></property>
		<property name="user" value="root"></property>
		<property name="password" value="1234"></property>
	</bean>

4.5 使用JdbcDaoSupport

4.5.1 dao层

在这里插入图片描述

4.5.2 spring配置文件
	<!-- 配置dao 
		* dao 继承 JdbcDaoSupport,之后只需要注入数据源,底层将自动创建模板
	-->
	<bean id="userDaoId" class="com.itheima.e_jdbcdaosupport.UserDao">
		<property name="dataSource" ref="dataSourceId"></property>
	</bean>
4.5.3 源码分析

在这里插入图片描述

4.6 配置properties

4.6.1 properties文件
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/ee19_spring_day02
jdbc.user=root
jdbc.password=1234
4.6.2 spring配置
<!-- 加载配置文件 
		"classpath:"前缀表示 src下
		在配置文件之后通过  ${key} 获得内容
	-->
	<context:property-placeholder location="classpath:com/itheima/f_properties/jdbcInfo.properties"/>
	
	<!-- 创建数据源 c3p0-->
	<bean id="dataSourceId" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="${jdbc.driverClass}"></property>
		<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
		<property name="user" value="${jdbc.user}"></property>
		<property name="password"  value="${jdbc.password}"></property>
	</bean>

5 要求

properties +  JdbcDaoSupport  + c3p0
UserDao  --> api ( update / query  / queryForObject)

1 spring day02回顾

  • AOP :切面编程
    切面:切入点 和 通知 结合
  • spring aop 编程
    aop:config
    方法1:
    <aop:pointcut expression=“切入点表达式” id=“”>
    <aop:advisor advice-ref=“通知引用” pointcut-ref=“切入点的引用”>

方法2:
<aop:advisor advice-ref=“通知引用” pointcut=“切入点表达式”>

  • AspectJ xml
    aop:config
    <aop:aspect ref=“切面类”>
    aop:pointcut
    aop:before 前置
    <aop:afterReturning returning=“第二个参数名称”> 后置
    aop:around 环绕
    <aop:afterThrowing throwing=“第二。。。”> 抛出异常
    aop:after 最终

  • AspectJ annotation
    @Aspect
    @Pointcut(“表达式”) private void xxx(){}
    @Before @…

  • 切入点表达式
    <aop:pointcut expression=“execution(* com.itheima.crm..service….*(…))” id=“”>

2 事务管理

2.1 回顾事务

  • 事务:一组业务操作ABCD,要么全部成功,要么全部不成功。

  • 特性:ACID
    原子性:整体、事务是一个不可分割的整体
    一致性:完成、事务执行的前后数据的完整性保持一致
    隔离性:并发、一个事务执行的过程中,不应该受到其他事务的干扰
    持久性:结果、事务一旦执行结束,数据就持久化到数据库

  • 隔离问题(事务引发的安全问题):
    脏读:一个事务读到另一个事务没有提交的数据,再次读取时另一个事务可能回滚
    不可重复读:一个事务读到另一个事务已提交的数据(update),多次读取修改前后的数据不一致
    虚读(幻读):一个事务读到另一个事务已提交的数据(insert),行数不一样

  • 隔离级别:
    read uncommitted:读未提交。存在3个问题,效率最高的。
    read committed:读已提交。解决脏读,存在2个问题,Oracle默认级别
    repeatable read:可重复读。解决:脏读、不可重复读,存在1个问题。mysql默认级别
    serializable :串行化。都解决,单事务。

  • mysql 事务操作–简单
    ABCD 一个事务
    Connection conn = null;
    try{
    //1 获得连接
    conn = …;
    //2 开启事务
    conn.setAutoCommit(false);
    A
    B
    C
    D
    //3 提交事务
    conn.commit();
    } catche(){
    //4 回滚事务
    conn.rollback();
    }

  • mysql 事务操作–Savepoint
    需求:AB(必须),CD(可选)
    Connection conn = null;
    Savepoint savepoint = null; //保存点,记录操作的当前位置,之后可以回滚到指定的位置。(可以回滚一部分)
    try{
    //1 获得连接
    conn = …;
    //2 开启事务
    conn.setAutoCommit(false);
    A
    B
    savepoint = conn.setSavepoint();
    C
    D
    //3 提交事务
    conn.commit();
    } catche(){
    if(savepoint != null){ //CD异常
    // 回滚到CD之前
    conn.rollback(savepoint);
    // 提交AB
    conn.commit();
    } else{ //AB异常
    // 回滚AB
    conn.rollback();
    }
    }

2.2 事务管理介绍

2.2.1 导入jar包

transaction --> tx

2.2.2 三个顶级接口
  • PlatformTransactionManager 平台事务管理器,spring要管理事务,必须使用事务管理器进行事务配置时,必须配置事务管理器。
  • TransactionDefinition:事务详情(事务定义、事务属性),spring用于确定事务具体详情,例如:隔离级别、传播行、为是否只读、超时时间等进行事务配置时,必须配置详情。spring将配置项封装到该对象实例。
  • TransactionStatus:事务状态,spring用于记录当前事务运行状态。例如:是否有保存点,事务是否完成。spring底层根据状态进行相应操作。
2.2.3 PlatformTransactionManager(平台事务管理器)
  • 导入jar包:需要时平台事务管理器的实现类
  • 会根据使用的操作数据库的技术选择对应的事物管理器
  • 常见的事务管理器(真正使用的管理器)
    DataSourceTransactionManager ,jdbc开发时事务管理器,采用JdbcTemplate或者Mybatis框架中使用
    HibernateTransactionManager,hibernate开发时事务管理器,整合hibernate
    在这里插入图片描述
  • api详解(PlatformTransactionManager)
    TransactionStatus getTransaction(TransactionDefinition definition) ,事务管理器 通过“事务详情”,获得“事务状态”,从而管理事务。
    void commit(TransactionStatus status) 根据状态提交
    void rollback(TransactionStatus status) 根据状态回滚
2.2.4 TransactionStatus(事务状态)
  • 来记录事物的状态信息
2.2.5 TransactionDefinition(事务定义/详情)
  • 传播行为:在两个业务之间如何共享事务。

    指如果在开始当前事务B之前,一个事务A已经存在,此时会有若干个选项可以执行一个事务方法啊的执行行为,有7大传播行为如下:
    只有前面三种是支持当前事务的,后面的都是不支持当前事务的。

    PROPAGATION_REQUIRED=0 , required , 必须  【默认值】
    	支持当前事务,A如果有事务,B将使用该事务。
    	如果A没有事务,B将创建一个新的事务。
    PROPAGATION_SUPPORTS=1 ,supports ,支持
    	支持当前事务,A如果有事务,B将使用该事务。
    	如果A没有事务,B将以非事务执行。
    PROPAGATION_MANDATORY=2,mandatory ,强制
    	支持当前事务,A如果有事务,B将使用该事务。
    	如果A没有事务,B将抛异常。
    PROPAGATION_REQUIRES_NEW=3 , requires_new ,必须新的
    	如果A有事务,将A的事务挂起,B创建一个新的事务
    	如果A没有事务,B创建一个新的事务
    PROPAGATION_NOT_SUPPORTED=4 ,not_supported ,不支持
    	如果A有事务,将A的事务挂起,B将以非事务执行
    	如果A没有事务,B将以非事务执行
    PROPAGATION_NEVER=5 ,never,从不
    	如果A有事务,B将抛异常
    	如果A没有事务,B将以非事务执行
    PROPAGATION_NESTED=6 ,nested ,嵌套
    	A和B底层采用保存点机制,形成嵌套事务。 
    	如果没有A则执行和0类似的。
    

    掌握:PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED
    非事务的方式比较少用

  • 隔离级别
    ISOLATION_DEFAULT=-1,默认没有
    ISOLATION_READ_UNCOMMITTED=1,读未提交
    ISOLATION_READ_COMMITTED=2,读已提交
    ISOLATION_REPEATABLE_READ=4,可重复读
    ISOLATION_SERIALIZABLE=8,串行化
2.2.6 Spring事务管理

平台事物管理器(PlatformTransactionManager)根据事务的定义信息(TransactionDefinition)进行事务管理
事务管理过程中会产生一些状态,这些状态会记录到事物状态(TransactionStatus)里面

2.2.7 事务分类
  • 事务类型

    事务一般分为两种:
    1.本地事务:就是指jdbc的。涉及到的就是本地的一个数据库
    2.分布式事务:就是指jta的。涉及到 分布式多个数据库

  • spring事务分类

    编程式事务(了解):通过编程代码在业务逻辑需要时自行实现
    声明式事务(掌握):通过xml或者注解实现,基于AOP

2.3 案例:转账

2.3.1 搭建环境
2.3.1.1 创建表
create database ee19_spring_day03;
use ee19_spring_day03;
create table account(
  id int primary key auto_increment,
  username varchar(50),
  money int
);
insert into account(username,money) values('jack','10000');
insert into account(username,money) values('rose','10000');
2.3.1.2 导入jar包
  • 核心:4+1
  • aop : 4 (aop联盟、spring aop、aspectj规范、spring aspect)
  • 数据库:2 (jdbc/tx)
  • 驱动:mysql
  • 连接池:c3p0
2.3.1.3 dao层
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {

	@Override
	public void out(String outer, Integer money) {
		this.getJdbcTemplate().update("update account set money = money - ? where username = ?", money,outer);
	}

	@Override
	public void in(String inner, Integer money) {
		this.getJdbcTemplate().update("update account set money = money + ? where username = ?", money,inner);
	}

}
2.3.1.4 service层
public class AccountServiceImpl implements AccountService {

	private AccountDao accountDao;
	public void setAccountDao(AccountDao accountDao) {
		this.accountDao = accountDao;
	}
	@Override
	public void transfer(String outer, String inner, Integer money) {
		accountDao.out(outer, money);
		//断电
//		int i = 1/0;
		accountDao.in(inner, money);
	}

}
2.3.1.5 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"
	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
       					   http://www.springframework.org/schema/context 
       					   http://www.springframework.org/schema/context/spring-context.xsd">

	<!-- 1 datasource -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/ee19_spring_day03"></property>
		<property name="user" value="root"></property>
		<property name="password" value="1234"></property>
	</bean>
	
	<!-- 2 dao  -->
	<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 3 service -->
	<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
		<property name="accountDao" ref="accountDao"></property>
	</bean>
2.3.1.6 测试
	@Test
	public void demo01(){
		String xmlPath = "applicationContext.xml";
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
		AccountService accountService =  (AccountService) applicationContext.getBean("accountService");
		accountService.transfer("jack", "rose", 1000);
	}
2.3.2 手动管理事务(了解)
  • spring底层使用 TransactionTemplate 事务模板进行操作。
  • 操作
  1. service 需要获得 TransactionTemplate
  2. spring 配置模板,并注入给service
  3. 模板需要注入事务管理器
  4. 配置事务管理器:DataSourceTransactionManager ,需要注入DataSource
2.3.2.1 Dao类
import org.springframework.jdbc.core.support.JdbcDaoSupport;

public class AccountDaoImple extends JdbcDaoSupport implements AccountDao {

	@Override
	public void out(String outer, int money) {
		this.getJdbcTemplate().update("update account set money = money - ? where name = ?",money,outer);
	}

	@Override
	public void in(String inner, int money) {
		this.getJdbcTemplate().update("update account set money = money + ? where name = ?", money,inner);
	}
}
2.3.2.2 修改service
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

public class AccountServiceImpl implements AccountService {
	private AccountDao accountDao;
	public void setAccountDao(AccountDao accountDao) {
		this.accountDao = accountDao;
	}

	//需要spring注入模板
	private TransactionTemplate transactionTemplate;
	public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
		this.transactionTemplate = transactionTemplate;
	}
	@Override
	public void transfer(final String outer,final String inner,final Integer money) {
		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
			
			@Override
			protected void doInTransactionWithoutResult(TransactionStatus arg0) {
				accountDao.out(outer, money);
				//断电
//				int i = 1/0;
				accountDao.in(inner, money);
			}
		});
	}
}
2.3.2.3 修改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"
	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
       					   http://www.springframework.org/schema/context 
       					   http://www.springframework.org/schema/context/spring-context.xsd">

	<!-- 创建数据源 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/study"></property>
		<property name="user" value="root"></property>
		<property name="password" value="10086"></property>
	</bean>
	
	<!-- 配置dao -->
	<bean id="accountDaoImple" class="cn.lm.tx01.AccountDaoImple">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- 配置service -->
	<bean id="accountServiceImplId" class="cn.lm.tx01.AccountServiceImpl">
		<property name="accountDao" ref="accountDaoImple"></property>
		<property name="transactionTemplate" ref="transactionTemplate"></property>
	</bean>
	
	<!-- 创建模板 -->
	<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
		<property name="transactionManager" ref="txManager"></property>
	</bean>
	
	<!-- 配置事务管理器 ,管理器需要事务,事务从Connection获得,连接从连接池DataSource获得 -->
	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
</beans>  
2.3.2.4 测试
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

	public static void main(String[] args) {
		String xmlPath = "cn/lm/tx01/applicationContext.xml";
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
		AccountService accountService = (AccountService) applicationContext.getBean("accountServiceImplId");
		accountService.transfer("jack", "rose", 1000);
	}
}
2.3.3 工厂bean 生成代理:半自动
  • spring提供 管理事务的代理工厂bean TransactionProxyFactoryBean
  1. getBean() 获得代理对象
  2. spring 配置一个代理
2.3.3.1 Dao类
import org.springframework.jdbc.core.support.JdbcDaoSupport;

public class AccountDaoImple extends JdbcDaoSupport implements AccountDao {

	@Override
	public void out(String outer, int money) {
		this.getJdbcTemplate().update("update account set money = money - ? where name = ?",money,outer);
	}

	@Override
	public void in(String inner, int money) {
		this.getJdbcTemplate().update("update account set money = money + ? where name = ?", money,inner);
	}
}
2.3.3.2 Service类
public class AccountServiceImpl implements AccountService {

	private AccountDao accountDao;

	public void setAccountDao(AccountDao accountDao) {
		this.accountDao = accountDao;
	}

	@Override
	public void transfer(String outer, String inner, int money) {
		accountDao.out(outer, money);
		int i = 1 / 0;
		accountDao.in(inner, money);
	}
}
2.3.3.3 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"
	 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
       					   http://www.springframework.org/schema/context 
       					   http://www.springframework.org/schema/context/spring-context.xsd">

	<!-- 创建数据源 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/study"></property>
		<property name="user" value="root"></property>
		<property name="password" value="10086"></property>
	</bean>
	
	<!-- 配置dao -->
	<bean id="accountDaoImple" class="cn.lm.tx02.AccountDaoImple">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- 配置service -->
	<bean id="accountServiceImplId" class="cn.lm.tx02.AccountServiceImpl">
		<property name="accountDao" ref="accountDaoImple"></property>
	</bean>
	
	<!-- 配置事务管理器 -->
	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- 4 service 代理对象 
		4.1 proxyInterfaces 接口 
		4.2 target 目标类
		4.3 transactionManager 事务管理器
		4.4 transactionAttributes 事务属性(事务详情)
			prop.key :确定哪些方法使用当前事务配置
			prop.text:用于配置事务详情
				格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception
					传播行为		隔离级别	是否只读		异常回滚		异常提交
				例如:
					<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop> 默认传播行为,和隔离级别
					<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly</prop> 只读
					<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,+java.lang.ArithmeticException</prop>  有异常扔提交 -->
	<bean id="proxyAccountService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<property name="proxyInterfaces" value="cn.lm.tx02.AccountService"></property>
		<property name="target" ref="accountServiceImplId"></property>
		<property name="transactionManager" ref="txManager"></property>
		<property name="transactionAttributes">
			<props>
				<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop>
			</props>
		</property>
	</bean>
</beans>	
2.3.3.4 测试
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

	public static void main(String[] args) {
		String xmlPath = "cn/lm/tx02/applicationContext.xml";
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
		AccountService accountService =  (AccountService) applicationContext.getBean("proxyAccountService");
		accountService.transfer("jack", "rose", 1000);
	}
}
2.3.4 AOP 配置基于xml【掌握】
  • 在spring xml 配置aop 自动生成代理,进行事务的管理
  1. 配置管理器
  2. 配置事务详情
  3. 配置aop
2.3.4.1 Dao
import org.springframework.jdbc.core.support.JdbcDaoSupport;

public class AccountDaoImple extends JdbcDaoSupport implements AccountDao {

	@Override
	public void out(String outer, int money) {
		this.getJdbcTemplate().update("update account set money = money - ? where name = ?",money,outer);
	}

	@Override
	public void in(String inner, int money) {
		this.getJdbcTemplate().update("update account set money = money + ? where name = ?", money,inner);
	}
}
2.3.4.2 Service
public class AccountServiceImpl implements AccountService {

	private AccountDao accountDao;

	public void setAccountDao(AccountDao accountDao) {
		this.accountDao = accountDao;
	}

	@Override
	public void transfer(String outer, String inner, int money) {
		accountDao.out(outer, money);
		int i = 1 / 0;
		accountDao.in(inner, money);
	}
}
2.3.4.3 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
       					   http://www.springframework.org/schema/beans/spring-beans.xsd
       					   http://www.springframework.org/schema/aop 
       					   http://www.springframework.org/schema/aop/spring-aop.xsd
       					   http://www.springframework.org/schema/context 
       					   http://www.springframework.org/schema/context/spring-context.xsd
       					   http://www.springframework.org/schema/tx 
       					   http://www.springframework.org/schema/tx/spring-tx.xsd">

	<!-- 创建数据源 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/study"></property>
		<property name="user" value="root"></property>
		<property name="password" value="10086"></property>
	</bean>
	
	<!-- 配置dao -->
	<bean id="accountDaoImple" class="cn.lm.tx03_xml.AccountDaoImple">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- 配置service -->
	<bean id="accountServiceImplId" class="cn.lm.tx03_xml.AccountServiceImpl">
		<property name="accountDao" ref="accountDaoImple"></property>
	</bean>
	
	<!-- 配置事务管理器 -->
	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- 配置 事务详情(事务通知)  , 在aop筛选基础上,对ABC三个确定使用什么样的事务。例如:AC读写、B只读 等
	<tx:attributes> 用于配置事务详情(属性属性)
		<tx:method name=""/> 详情具体配置
			propagation 传播行为 , REQUIRED:必须;REQUIRES_NEW:必须是新的,一般不写,保持默认
			isolation 隔离级别 一般不写,保持默认即可
			rollback-for="" 什么时候回滚,一般就是异常的时候,一般不写
			-->
	<tx:advice id="txAdvice" transaction-manager="txManager">
		<tx:attributes>
			<tx:method name="transfer" propagation="REQUIRED" isolation="DEFAULT"/>
		</tx:attributes>
	</tx:advice>
	
	
	<!--
			上面的method里面的name就是具体要做事物的方法
			相当于对下面的切点做了过滤,虽然配置了serviceImpl包下所有方法
			但实际事物管理的方法在这里过滤
			可以配置多个,如下:
			表示只对以add、del、upd、get、set、logi、regi开头的方法起作用
			
			<tx:advice id="interceptor" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="add*"/>
            <tx:method name="del*"/>
            <tx:method name="upd*"/>
            <tx:method name="get*"/>
            <tx:method name="set*"/>
            <tx:method name="logi*"/>
            <tx:method name="regi*"/>
            <!--对于查询的方法,可以不配或者配置只读-->
            <tx:method name="login" read-only="true"/>
        </tx:attributes>
    </tx:advice>
			如果需要给所有方法配置,可以直接写*,表示所有的
			切点方法,都需要拦截
			<tx:method name="*"/>
			-->
	
	
	<!-- AOP编程,目标类有ABCD(4个连接点),切入点表达式 确定增强的连接器,从而获得切入点:ABC -->
	<aop:config>
		<aop:advisor advice-ref="txAdvice" pointcut="execution(* cn.lm.tx03_xml.*.*(..))"/>
	</aop:config>
</beans>
2.3.4.4 测试
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

	public static void main(String[] args) {
		String xmlPath = "cn/lm/tx03_xml/applicationContext.xml";
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
		AccountService accountService =  (AccountService) applicationContext.getBean("accountServiceImplId");
		accountService.transfer("jack", "rose", 1000);
	}
}
2.3.5 AOP配置基于注解【掌握】
  1. 配置事务管理器,将并事务管理器交予spring
  2. 在目标类或目标方法添加注解即可 @Transactional
2.3.5.1 Service层
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.DEFAULT)
public class AccountServiceImpl implements AccountService {

	private AccountDao accountDao;

	public void setAccountDao(AccountDao accountDao) {
		this.accountDao = accountDao;
	}

	@Override
	public void transfer(String outer, String inner, int money) {
		accountDao.out(outer, money);
		//int i = 1 / 0;
		accountDao.in(inner, money);
	}
}
2.3.5.2 spring配置
<!-- 4 事务管理 -->
	<!-- 4.1 事务管理器 -->
	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 4.2 将管理器交予spring 
		* transaction-manager 配置事务管理器
		* proxy-target-class
			true : 底层强制使用cglib 代理
	-->
	<!--开启注解-->
	<tx:annotation-driven transaction-manager="txManager"/>
2.3.5.3 事务详情配置

@Transactional(propagation=Propagation.REQUIRED , isolation = Isolation.DEFAULT)
public class AccountServiceImpl implements AccountService {

  • 放在类上面表示类中所有的方法都会进行事务管理
  • 放在单独的某个方法上面表示该方法被事务管理
  • 如果类跟方法上同时有注解,则方法上的注解会覆盖类上的注解

3 整合Junit

  • 导入jar包
    基本 :4+1
    测试:spring-test…jar
  1. 让Junit通知spring加载配置文件
  2. 让spring容器自动进行注入
  • 修改测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class TestApp {
	
	@Autowired  //与junit整合,不需要在spring xml配置扫描
	private AccountService accountService;
	
	@Test
	public void demo01(){
//		String xmlPath = "applicationContext.xml";
//		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
//		AccountService accountService =  (AccountService) applicationContext.getBean("accountService");
		accountService.transfer("jack", "rose", 1000);
	}

}

4 整合web

  1. 导入jar包
    spring-web.xml

  2. tomcat启动加载配置文件
    servlet --> init(ServletConfig) --> 2
    filter --> init(FilterConfig) --> web.xml注册过滤器自动调用初始化
    listener --> ServletContextListener --> servletContext对象监听【】
    spring提供监听器 ContextLoaderListener --> web.xml …
    如果只配置监听器,默认加载xml位置:/WEB-INF/applicationContext.xml

  3. 确定配置文件位置,通过系统初始化参数
    ServletContext 初始化参数 web.xml

    	<context-param>
    		<param-name>contextConfigLocation
    		<param-value>classpath:applicationContext.xml
    
  <!-- 确定配置文件位置 -->
  <context-param>
  	<param-name>contextConfigLocation</param-name>
  	<param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  
  <!-- 配置spring 监听器,加载xml配置文件 -->
  <listener>
  	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  1. 从servletContext作用域 获得spring容器 (了解)
    // 从application作用域(ServletContext)获得spring容器
    //方式1: 手动从作用域获取
    ApplicationContext applicationContext =
    (ApplicationContext) this.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
    //方式2:通过工具获取
    ApplicationContext apppApplicationContext2 =
    WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());

5 SSH整合

5.1 jar整合

struts:2.3.15.3
hibernate : 3.6.10
spring: 3.2.0

5.1.1 struts

struts-2.3.15.3\apps\struts2-blank\WEB-INF\lib

模板技术 ,一般用于页面静态化
freemarker:扩展名:*.ftl
velocity :扩展名 *.vm

5.1.2 spring
  • 基础:4+1 , beans、core、context、expression , commons-logging (struts已经导入)

  • AOP:aop联盟、spring aop 、aspect规范、spring aspect

  • db:jdbc、tx

  • 测试:test

  • web开发:spring web

  • 驱动:mysql

  • 连接池:c3p0

  • 整合hibernate:spring orm

5.1.3 hibernate

%h%\hibernate3.jar 核心
%h%\lib\required 必须

%h%\lib\jpa jpa规范 (java persistent api 持久api),hibernate注解开发 @Entity @Id 等

  • 整合log4j
    导入 log4j…jar (struts已经导入)
    整合(过渡):slf4j-log4j12-1.7.5.jar

  • 二级缓存
    核心:ehcache-1.5.0.jar
    依赖:
    backport-util-concurrent-2.1.jar
    commons-logging (存在)

5.1.4 整合包
  • spring整合hibernate: spring orm
  • struts 整合spring:struts2-spring-plugin-2.3.15.3.jar

删除重复jar包

5.2 spring整合hibernate:有hibernate.cfg.xml

5.2.1 创建表
create table t_user(
  id int primary key auto_increment,
  username varchar(50),
  password varchar(32),
  age int 
);
5.2.2 PO 类
  • javabean
public class User {
	private Integer id;
	private String username;
	private String password;
	private Integer age;
  • 映射文件
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
	<class name="com.itheima.domain.User" table="t_user">
		<id name="id">
			<generator class="native"></generator>
		</id>
		<property name="username"></property>
		<property name="password"></property>
		<property name="age"></property>
	</class>

</hibernate-mapping>
5.2.3 dao层
  • spring提供 HibernateTemplate 用于操作PO对象,类似Hibernate Session对象。
public class UserDaoImpl implements UserDao {
	
	//需要spring注入模板
	private HibernateTemplate hibernateTemplate;
	public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
		this.hibernateTemplate = hibernateTemplate;
	}

	@Override
	public void save(User user) {
		this.hibernateTemplate.save(user);
	}

}
5.2.4 service层
public class UserServiceImpl implements UserService {

	private UserDao userDao;
	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}
	@Override
	public void register(User user) {
		userDao.save(user);
	}

}
5.2.5 hibernate.cfg.xml
<session-factory>
		<!-- 1基本4项 -->
		<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
		<property name="hibernate.connection.url">jdbc:mysql:///ee19_spring_day03</property>
		<property name="hibernate.connection.username">root</property>
		<property name="hibernate.connection.password">1234</property>
		
		<!-- 2 配置方言 -->
		<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
		
		<!-- 3 sql语句 -->
		<property name="hibernate.show_sql">true</property>
		<property name="hibernate.format_sql">true</property>
		
		<!-- 4 自动生成表(一般没用) -->
		<property name="hibernate.hbm2ddl.auto">update</property>
		
		<!-- 5本地线程绑定 -->
		<property name="hibernate.current_session_context_class">thread</property>
		
		<!-- 导入映射文件 -->
		<mapping resource="com/itheima/domain/User.hbm.xml"/>
	
	</session-factory>
5.2.6 applicationContext.xml
5.2.6.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:tx="http://www.springframework.org/schema/tx"
       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/tx 
       					   http://www.springframework.org/schema/tx/spring-tx.xsd
       					   http://www.springframework.org/schema/aop 
       					   http://www.springframework.org/schema/aop/spring-aop.xsd
       					   http://www.springframework.org/schema/context 
       					   http://www.springframework.org/schema/context/spring-context.xsd">

5.2.6.2 加载hibernate配置文件
<!-- 1 加载hibenrate.cfg.xml 获得SessionFactory 
		* configLocation确定配置文件位置
	-->
	<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
		<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
	</bean>
	
	<!-- 2创建模板 
		* 底层使用session,session 有sessionFactory获得
	-->
	<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
		<property name="sessionFactory" ref="sessionFactory"></property>
	</bean>
5.2.6.3 dao和service
<!-- 3 dao -->
	<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
		<property name="hibernateTemplate" ref="hibernateTemplate"></property>
	</bean>
	
	<!-- 4 service -->
	<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
		<property name="userDao" ref="userDao"></property>
	</bean>
5.2.6.4 事务管理
<!-- 5 事务管理 -->
	<!-- 5.1 事务管理器 :HibernateTransactionManager -->
	<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" >
		<property name="sessionFactory" ref="sessionFactory"></property>
	</bean>
	<!-- 5.2 事务详情 ,给ABC进行具体事务设置 -->
	<tx:advice id="txAdvice" transaction-manager="txManager">
		<tx:attributes>
			<tx:method name="register"/>
		</tx:attributes>
	</tx:advice>
	<!-- 5.3 AOP编程,ABCD 筛选 ABC  -->
	<aop:config>
		<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.itheima.service..*.*(..))"/>
	</aop:config>
5.2.7 测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class TestApp {
	
	@Autowired
	private UserService userService;
	
	@Test
	public void demo01(){
		User user = new User();
		user.setUsername("jack");
		user.setPassword("1234");
		user.setAge(18);
		
		userService.register(user);
	}
}

5.3 spring整合hibernate:没有hibernate.cfg.xml 【】

  • 删除hibernate.cfg.xml文件,但需要保存文件内容,将其配置spring中
  • 修改dao层,继承HibernateDaoSupport
5.3.1 修改spring,配置SessionFactory
<!-- 1.1加载properties文件 -->
	<!-- 1.2 配置数据源 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql:///ee19_spring_day03"></property>
		<property name="user" value="root"></property>
		<property name="password" value="1234"></property>
	</bean>
	
	<!-- 1.3配置 LocalSessionFactoryBean,获得SessionFactory 
		* configLocation确定配置文件位置
			<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
		1)dataSource 数据源
		2)hibernateProperties hibernate其他配置项
		3) 导入映射文件
			mappingLocations ,确定映射文件位置,需要“classpath:” ,支持通配符 【】
				<property name="mappingLocations" value="classpath:com/itheima/domain/User.hbm.xml"></property>
				<property name="mappingLocations" value="classpath:com/itheima/domain/*.hbm.xml"></property>
			mappingResources ,加载执行映射文件,从src下开始 。不支持通配符*
				<property name="mappingResources" value="com/itheima/domain/User.hbm.xml"></property>
			mappingDirectoryLocations ,加载指定目录下的,所有配置文件
				<property name="mappingDirectoryLocations" value="classpath:com/itheima/domain/"></property>
			mappingJarLocations , 从jar包中获得映射文件
	-->
	<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
		<property name="dataSource" ref="dataSource"></property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.format_sql">true</prop>
				<prop key="hibernate.hbm2ddl.auto">update</prop>
				<prop key="hibernate.current_session_context_class">thread</prop>
			</props>
		</property>
		<property name="mappingLocations" value="classpath:com/itheima/domain/*.hbm.xml"></property>
	</bean>
5.3.2 修改dao,使用HibernateDaoSupport
  • 继承HibernateDaoSupport
// 底层需要SessionFactory,自动创建HibernateTemplate模板
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {

	@Override
	public void save(User user) {
		this.getHibernateTemplate().save(user);
	}

}
  • spring 删除模板,给dao注入SessionFactory
	<!-- 3 dao -->
	<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
		<property name="sessionFactory" ref="sessionFactory"></property>
	</bean>

5.4 struts整合spring:spring创建action

  1. 编写action类,并将其配置给spring ,spring可以注入service
  2. 编写struts.xml
  3. 表单jsp页面
  4. web.xml 配置
    1. 确定配置文件contextConfigLocation
    2. 配置监听器 ContextLoaderListener
    3. 配置前端控制器 StrutsPrepareAndExecuteFitler
5.4.1 action类
  • 通用
public class UserAction extends ActionSupport implements ModelDriven<User> {

	//1 封装数据
	private User user = new User();

	@Override
	public User getModel() {
		return user;
	}
	
	//2 service
	private UserService userService;
	public void setUserService(UserService userService) {
		this.userService = userService;
	}
  • 功能
/**
	 * 注册
	 * @return
	 */
	public String register(){
		userService.register(user);
		return "success";
	}
5.4.2 spring配置
<!-- 6 配置action -->
	<bean id="userAction" class="com.itheima.web.action.UserAction" scope="prototype">
		<property name="userService" ref="userService"></property>
	</bean>
5.4.3 struts配置
<struts>
	<!-- 开发模式 -->
    <constant name="struts.devMode" value="true" />

    <package name="default" namespace="/" extends="struts-default">
    	<!-- 底层自动从spring容器中通过名称获得内容, getBean("userAction") -->
    	<action name="userAction_*" class="userAction" method="{1}">
    		<result name="success">/messag.jsp</result>
    	</action>
    </package>
</struts>
5.4.4 jsp表单
<form action="${pageContext.request.contextPath}/userAction_register" method="post">
		用户名:<input type="text" name="username"/> <br/>
		密码:<input type="password" name="password"/> <br/>
		年龄:<input type="text" name="age"/> <br/>
		<input type="submit" />
	</form>
5.4.5 配置web.xml
<!-- 1 确定spring xml位置 -->
  <context-param>
  	<param-name>contextConfigLocation</param-name>
  	<param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  <!-- 2 spring监听器 -->
  <listener>
  	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <!-- 3 struts 前端控制器 -->
  <filter>
  	<filter-name>struts2</filter-name>
  	<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>struts2</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>

5.5 struts整合spring:struts创建action 【】

  • 删除spring action配置
  • struts
<package name="default" namespace="/" extends="struts-default">
    	<!-- 底层自动从spring容器中通过名称获得内容, getBean("userAction") -->
    	<action name="userAction_*" class="com.itheima.web.action.UserAction" method="{1}">
    		<result name="success">/messag.jsp</result>
    	</action>
    </package>
  • 要求:Action类中,必须提供service名称与 spring配置文件一致。(如果名称一样,将自动注入)

分析:

  1. struts 配置文件
    default.properties ,常量配置文件
    struts-default.xml ,默认核心配置文件
    struts-plugins.xml ,插件配置文件
    struts.xml,自定义核心配置文件
    常量的使用,后面配置项,将覆盖前面的。

  2. default.properties ,此配置文件中确定 按照【名称】自动注入
    /org/apache/struts2/default.properties

  3. struts-plugins.xml ,struts整合spring

     <constant name="struts.objectFactory" value="spring" />
    

    struts的action将有spring创建

总结,之后action有spring创建,并按照名称自动注入

6 要求

1 spring day03回顾

1.1 事务管理

  • 基于xml配置
  1. 配置事务管理器
    jdbc:DataSourceTransactionManager
    hibernate:HibernateTransactionManager
  2. 事务通知(详情、属性)
<tx:advice id="" transaction-manager="">
  <tx:attributes>
     <tx:method name="add*">
     <tx:method name="update*">
     <tx:method name="delete*">
     <tx:method name="find* read-only="true">
  1. AOP编程,ABCD–> ABC
<aop:config>
  <aop:advisor advice-ref="txAdvice"  pointcut="execution(* com..*.*(..))">
  • 基于注解
    xml 配置
  1. 事务管理器

  2. 将配置事务管理器交予spring
    <tx:annotation-driven transaction-manager=“…”>

目标类
@Transactional 类 | 方法

1.2 整合Junit

@RunWith(SpringJunit4RnnerClass.class)
@ContextConfiguration(locations=“classpath:…xml”)

@Autowired 注入

@Test 测试

1.3 整合web

web.xml 配置

  1. 确定xml位置

    name:contextConfigLocation
    value:classpath:…xml
  2. 加载xml文件,配置监听器
    ContextLoaderListener

1.4 整合

  1. hibernate po (domain、bean)
  2. dao层:
    需要HibernateTemplate 相当于session操作PO类 --> 必须提供setter方法,让spring注入,xml配置模板
    save() update delete saveOrUpdate find
    继承HibernateDaoSupport,需要注入SessionFactory,底层自动创建模板
    dao方法中 this.getHibernateTemplate()
  3. service 层,spring配置
    properties <context:property-placeholder location>
    配置数据源:ComboPooledDataSource
    配置SessionFactory:LocalSessionFactoryBean
    事务管理
  4. web层 ,aciton
    struts.xml 前面看到一位struts,底层使用spring
    默认与spring整合之后,按照【名称】自动注入

spring day04 – spring day07 ,案例(小项目)
day04: SVN 、搭建环境(完成PO类)
day05: 基本功能(struts拦截器、hibernate关联获取)
day06: 复杂操作(查询+分页+条件、ajax级联操作)
day07: 重写–工具 (BaseDao、BaseAction)

2 SVN

2.1 版本控制

2.1.1 什么版本控制
  • 版本控制(Revision Control):是维护工程蓝图的标准做法,能追踪工程蓝图从诞生一直到定案的过程。是一种记录若干文件内容变化,以便将来查阅特定版本修订情况的系统。也是一种软体工程技巧,籍以在开发的过程中,确保由不同人所编辑的同一档案都得到更新。
2.1.2 版本控制软件
  • CVS(Concurrent Versions System)代表协作版本系统或者并发版本系统,是一种版本控制系统,方便软件的开发和使用者协同工作。
  • VSS ( Visual Source Safe )只能在windows下,作为 Microsoft Visual Studio 的一名成员,它主要任务就是负责项目文件的管理
  • Git是用于Linux内核开发的版本控制工具。它采用了分布式版本库的方式,不必服务器端软件支持,使源代码的发布和交流极其方便。Git的速度很快,这对于诸如Linux kernel这样的大项目来说自然很重要。Git最为出色的是它的合并跟踪(merge tracing)能力。
    www.github.org
    。。。。。。
  • SVN(Subversion ),是一个开放源代码的版本控制系统,采用了分支管理系统,它的设计目标就是取代CVS。

2.2 SVN特点

  • 统一的版本号。CVS是对每个文件顺序编排版本号,在某一时间各文件的版本号各不相同。而Subversion下,任何一次提交都会对所有文件增加到同一个新版本号,即使是提交并不涉及的文件。所以,各文件在某任意时间的版本号是相同的。版本号相同的文件构成软件的一个版本。
  • 原子提交。一次提交不管是单个还是多个文件,都是作为一个整体提交的。在这当中发生的意外例如传输中断,不会引起数据库的不完整和数据损坏。
  • 重命名、复制、删除文件等动作都保存在版本历史记录当中。
  • 对于二进制文件,使用了节省空间的保存方法。(简单的理解,就是只保存和上一版本不同之处)
  • 目录也有版本历史。整个目录树可以被移动或者复制,操作很简单,而且能够保留全部版本记录。
  • 分支的开销非常小。
  • 优化过的数据库访问,使得一些操作不必访问数据库就可以做到。这样减少了很多不必要的和数据库主机之间的网络流量。
  • 支持元数据(Metadata)管理。每个目录或文件都可以定义属性(Property),它是一些隐藏的键值对,用户可以自定义属性内容,而且属性和文件内容一样在版本控制范围内。
  • 支持FSFS和Berkeley DB两种资料库格式。
  • 不足:只能设置目录的访问权限,无法设置单个文件的访问权限。

2.3 体系结构

2.4 安装

  • 测试安装

  • 检查path系统环境变量

2.5 创建仓库

  • 格式:cmd> svnadmin create 路径

  • 仓库目录结构

  • 注意:创建仓库时,目录必须是空的 ,及新建文件夹

2.6 启动

  • 格式:cmd> svnserve -d -r 仓库的路径
    -d后台执行
    -r版本库的根目录

启动时,指定“仓库路径”不同,分类:多仓库和单仓库

  • 多仓库【掌握】

    启动:svnserve -d -r 仓库父目录 ,表示启动时多仓库
    例如:svnserve -d -r G:\repository\svn
    访问:svn://localhost:3690/bbs

  • 单仓库

    启动:svnserve -d -r 仓库的根 ,表示启动时单仓库
    例如:svnserve -d -r G:\repository\svn\bbs
    访问:svn://localhost:3690

  • 将操作注册成操作系统的“服务”,开机启动。

  1. “运行”,services.msc 打开“服务”

  2. 删除“服务”

  3. 注册“服务”
    sc create svn binpath= “D:\java\Subversion\bin\svnserve.exe --service -r G:\repository\svn” displayname= “SVN-Service” start= auto depend= Tcpip

  4. 启动或停止“服务”

2.7 操作【掌握 思想】

2.7.1 checkout
  • 格式:svn checkout 服务器地址 下载地址
2.7.2 commit
  • 格式:svn commit 资源

问题1:没有纳入版本控制

使用add子命令 添加到本地版本库

问题2:没有编写日志

采用 -m  参数设置日志信息

问题3:没有权限

修改权限,设置匿名访问
	G:\repository\svn\bbs\conf\svnserve.conf
2.7.3 update
  • 格式: svn update

2.8 图形化:TortoiseSVN 安装

  • 安装成功之后,所有的操作都是“右键”

2.9 svn权限

  • 权限需要3个配置文件

  • svnserve.conf
    开启认证

    确定账号配置文件位置

    确定认证配置文件位置

  • passwd 账号配置 (一行一个账号,账号用户名和密码组成,使用等号分隔)

  • authz 认证配置文件
    配置组 , 格式:组名 = 用户1 ,用户2,…

    认证细节配置
    多仓库
    [bbs:/] --> 确定仓库名称 。[bbs:/doc] 给bbs仓库的doc目录配置权限
    @itheima = rw --> 给itheima组设置权限。
    read (‘r’) ,read-write (‘rw’) ,or no access (‘’).
    user3 = r --> 给user3 指定权限
    *= --> 其他用户没有权限

      单仓库
      	[/]				-->当仓库的根  [/doc]  单仓库doc目录
    

2.10 TortoiseSVN 常见图标

2.11 myeclipse svn 插件

2.11.1 安装插件
	如果3个都不能使用,直接换eclipse
  • 安装方式1:直接复制

    eclipse插件规范
    eclipse 目录
    | – features目录
    | – plugins 目录

  • 方式2:使用link文件
    将插件解压到任意目录(不含中文、空格),在myeclipse/dropins目录添加一个link文件
    文件名:自定义
    文件扩展名:link
    文件内容:
    path = 插件完整目录,需要指定到eclipse,及可以看到(features 、 plugins)
    例如:
    path=D:\java\MyEclipse\MyEclipse 10\svn\eclipse
    path=D:/java/MyEclipse/MyEclipse 10/svn/eclipse

  • 方式3:在线安装

  • 安装成功标志

2.11.2 操作

2.12 svn目录规范

trunk ,主线,用于存放程序整个进度
branches ,分支,例如:bug修复、特殊功能等
tags,标签(版本),此目录下的内容不能修改

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值