Spring概述
一、Spring是一个开源框架
二、Spring为简化企业级开发而生,使用Spring开发可以将Bean对象,Dao组件对象,Service组件对象等交给Spring容器来管理,这样使得很多复杂的代码在Spring中开发却变得非常的优雅和简洁,有效的降低代码的耦合度,极大的方便项目的后期维护、升级和扩展。
三、Spring是一个IOC(DI)和AOP容器框架。
四、Spring的优良特性
[1]非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的API
[2]控制反转:IOC——Inversion of Control,指的是将对象的创建权交给Spring去创建。使用Spring之前,对象的创建都是由我们自己在代码中new创建。而使用Spring之后。对象的创建都是由给了Spring框架。
[3]依赖注入:DI——Dependency Injection,是指依赖的对象不需要手动调用setXX方法去设置,而是通过配置赋值。
[4]面向切面编程:Aspect Oriented Programming——AOP
[5]容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期
[6]组件化:Spring实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。
[7]一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上Spring 自身也提供了表述层的SpringMVC和持久层的Spring JDBC)。
Spring的模块介绍
Spring框架分为四大模块:
Core核心模块,负责管理组件的Bean对象
spring- beans- 4.0 .0 . RELEASE. jar
spring- context- 4.0 .0 . RELEASE. jar
spring- core- 4.0 .0 . RELEASE. jar
spring- expression- 4.0 .0 . RELEASE. jar
面向切面编程
spring- aop- 4.0 .0 . RELEASE. jar
spring- aspects- 4.0 .0 . RELEASE. jar
数据库操作
spring- jdbc- 4.0 .0 . RELEASE. jar
spring- orm- 4.0 .0 . RELEASE. jar
spring- oxm- 4.0 .0 . RELEASE. jar
spring- tx- 4.0 .0 . RELEASE. jar
spring- jms- 4.0 .0 . RELEASE. jar
Web模块
spring- web- 4.0 .0 . RELEASE. jar
spring- webmvc- 4.0 .0 . RELEASE. jar
spring- websocket- 4.0 .0 . RELEASE. jar
spring- webmvc- portlet- 4.0 .0 . RELEASE. jar
IOC依赖注入
IOC(控制反转)
IOC 全称指的是 Inverse Of Control 控制反转。
使用Spring之前,我们对Bean对象的管制,都是自己手动的去new Xxx()。
而使用了Spring模型之后,我们把new的操作。交给Spring容器。
DI(依赖注入)
DI 指的是Dependency Injection 。是依赖注入的意思。
原来在使用Spring之前。
Class BookService{
private BookDao bookDao;
public void setBookDao( BookDao bookDao ){
this.bookDao = bookDao
}
}
使用了Spring之后。我们只需要使用xml配置,或者注解配置。就可以直接注入。
第一个IOC示例程序 – 通过id获取对象
测试:通过IOC容器创建对象,并为属性赋值★
1 、创建一个Java工程:
2 、创建log4j. properties日记配置文件
# Global logging configuration
log4j. rootLogger= INFO, stdout
# Console output. . .
log4j. appender. stdout= org. apache. log4j. ConsoleAppender
log4j. appender. stdout. layout= org. apache. log4j. PatternLayout
log4j. appender. stdout. layout. ConversionPattern= % 5 p [ % t] - % m% n
3 、创建Spring的配置文件
4 、创建一个JavaBean对象
public class Person {
private int id;
private String name;
private String phone;
private int age;
}
5 、到Spring配置文件中配置你的Bean对象
< ? xml version= "1.0" encoding= "UTF-8" ? >
< beans xmlns= "http://www.springframework.org/schema/beans"
xmlns: xsi= "http://www.w3.org/2001/XMLSchema-instance"
xsi: schemaLocation= "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" >
< ! -- bean标签用于配置一个组件对象(javaBean,Dao。Service)
id 是给bean对象起一个唯一的标识
class bean 对象的具体全类名
-- >
< bean id= "p1" class = "com.ddh.pojo.Person" >
< ! -- property标签用来配置属性信息
name 是属性名
value 是属性值
-- >
< property name= "id" value= "1" / >
< property name= "name" value= "华仔" / >
< property name= "age" value= "18" / >
< property name= "phone" value= "18699998888" / >
< / bean>
< / beans>
6 、从Spring容器中获取Bean对象
@Test
public void test1 ( ) throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext (
"application.xml" ) ;
Person person = ( Person) applicationContext. getBean ( "p1" ) ;
System. out. println ( person) ;
}
常见的错误:
指定的id不存在。找不到bean对象。
IOC示例程序 – 通过类型获取对象(重要)
测试:根据bean的类型从IOC容器中获取bean的实例★
在application. xml中的配置:
< ! -- bean标签用于配置一个组件对象(javaBean,Dao。Service)
id 是给bean对象起一个唯一的标识
class bean 对象的具体全类名
-- >
< bean id= "p1" class = "com.ddh.pojo.Person" >
< ! -- property标签用来配置属性信息
name 是属性名
value 是属性值
-- >
< property name= "id" value= "1" / >
< property name= "name" value= "华仔" / >
< property name= "age" value= "18" / >
< property name= "phone" value= "18699998888" / >
< / bean>
< bean id= "p2" class = "com.ddh.pojo.Person" >
< ! -- property标签用来配置属性信息
name 是属性名
value 是属性值
-- >
< property name= "id" value= "1" / >
< property name= "name" value= "华仔" / >
< property name= "age" value= "18" / >
< property name= "phone" value= "18699998888" / >
< / bean>
测试推荐:
@Test
public void test2 ( ) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext ( "application.xml" ) ;
Person person = applicationContext. getBean ( Person. class ) ;
System. out. println ( person) ;
}
常见错误说明:
当在applicationContext. xml配置文件中。有多个同Person. class 类型实现的时候。
IOC示例程序 – 通过构造方法参数名注入值
测试:通过构造器为bean的属性赋值
配置内容:
< bean id= "p3" class = "com.ddh.pojo.Person" >
< ! -- public Person ( int id, String name, String phone, int age) -- >
< constructor- arg name= "id" value= "3" / >
< constructor- arg name= "name" value= "p3" / >
< constructor- arg name= "phone" value= "13999998869" / >
< constructor- arg name= "age" value= "18" / >
< / bean>
测试代码:
@Test
public void test3 ( ) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext ( "application.xml" ) ;
Person person = ( Person) applicationContext. getBean ( "p3" ) ;
System. out. println ( person) ;
}
IOC示例程序 – index属性指定参数的位置
测试:通过index属性指定参数的位置
xml中的配置如下:
< bean id= "p4" class = "com.ddh.pojo.Person" >
< ! -- public Person ( int id, String name, String phone, int age) -- >
< ! --
constructor- arg 表示使用构造方法注入属性值
name 表示构造方法的参数名
index 表示构造方法的参数顺序从0 开始
value 表示要传入的构造方法的参数值
-- >
< constructor- arg value= "4" index= "0" / >
< constructor- arg value= "p4" index= "1" / >
< constructor- arg value= "13999998869" index= "2" / >
< constructor- arg value= "18" index= "3" / >
< / bean>
测试的代码:
@Test
public void test4 ( ) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext ( "application.xml" ) ;
Person person = ( Person) applicationContext. getBean ( "p4" ) ;
System. out. println ( person) ;
}
IOC示例程序 – 根据参数类型注入
测试: 根据参数类型注入
xml中的配置:
< bean id= "p5" class = "com.ddh.pojo.Person" >
< ! -- public Person ( int id, String name, String phone, int age) -- >
< ! -- public Person ( int id, String phone, int age, String name) -- >
< constructor- arg value= "5" index= "0" type= "int" / >
< constructor- arg value= "phone" index= "1" type= "java.lang.String" / >
< constructor- arg value= "10" index= "2" type= "java.lang.String" / >
< constructor- arg value= "20" index= "3" type= "int" / >
< / bean>
测试的代码:
@Test
public void test5 ( ) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext ( "application.xml" ) ;
Person person = ( Person) applicationContext. getBean ( "p5" ) ;
System. out. println ( person) ;
}
IOC之 P名称空间
测试:通过p名称空间为bean赋值
xml中的配置:
< bean id= "p6" class = "com.ddh.pojo.Person" p: id= "60" p: name= "第六个" p: phone= "6电话" p: age= "66" / >
测试的代码:
@Test
public void test6 ( ) throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext ( "application.xml" ) ;
Person person = ( Person) applicationContext. getBean ( "p6" ) ;
System. out. println ( person) ;
}
IOC之子对象的赋值测试(重要)
引用其他bean★
创建个新的工程。测试Spring的开发环境。
创建新的Bean对象
public class Car {
private int id;
private String name;
}
public class Person {
private int id;
private String name;
private String phone;
private int age;
private Car car;
}
在xml中的配置如下:
< bean id= "car1" class = "com.ddh.pojo.Car" >
< property name= "id" value= "1" / >
< property name= "name" value= "宝马" / >
< / bean>
< bean id= "car2" class = "com.ddh.pojo.Car" >
< property name= "id" value= "2" / >
< property name= "name" value= "马自达" / >
< / bean>
< bean id= "p7" class = "com.ddh.pojo.Person" >
< property name= "id" value= "7" / >
< property name= "name" value= "华仔7" / >
< property name= "age" value= "187" / >
< property name= "phone" value= "18679998888" / >
< ! -- name表示你要注入的哪个属性,ref 属性表示你要引用哪个对象 -- >
< property name= "car" ref= "car1" / >
< / bean>
测试的代码:
@Test
public void test7 ( ) throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext ( "application.xml" ) ;
Person person = ( Person) applicationContext. getBean ( "p7" ) ;
System. out. println ( person) ;
}
IOC之内部Bean的使用
引用内部bean
xml中配置的内容如下:
< bean id= "p8" class = "com.ddh.pojo.Person" >
< property name= "id" value= "8" / >
< property name= "name" value= "华仔8" / >
< property name= "age" value= "888" / >
< property name= "phone" value= "18688888888" / >
< ! -- name表示你要注入的哪个属性,ref 属性表示你要引用哪个对象 -- >
< property name= "car" >
< ! -- 内部的bean标签定义的对象。无法通过Spring容器获取。只能在内部赋值使用 -- >
< bean id= "innerCar" class = "com.ddh.pojo.Car" p: id= "22" p: name= "内部汽车" > < / bean>
< / property>
< / bean>
测试的代码:
@Test
public void test8 ( ) throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext ( "application.xml" ) ;
Person p8 = ( Person) applicationContext. getBean ( "p8" ) ;
System. out. println ( p8) ;
System. out. println ( applicationContext. getBean ( "innerCar" ) ) ;
}
常见错误:内部的Bean不能被外部使用
IOC之List属性的赋值
使用list子元素为List类型的属性赋值
public class Person {
private int id;
private String name;
private String phone;
private int age;
private Car car;
private List< Object> list;
}
xml中的配置:
< bean id= "p9" class = "com.ddh.pojo.Person" >
< property name= "id" value= "8" / >
< property name= "name" value= "华仔8" / >
< property name= "age" value= "888" / >
< property name= "phone" value= "18688888888" / >
< property name= "list" >
< list>
< value> list1< / value>
< value> list2< / value>
< value> list3< / value>
< / list>
< / property>
< / bean>
测试的代码:
@Test
public void test9 ( ) throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext ( "application.xml" ) ;
Person p9 = ( Person) applicationContext. getBean ( "p9" ) ;
System. out. println ( p9) ;
}
IOC之Map属性的赋值
使用map子元素为Map类型的属性赋值
public class Person {
private int id;
private String name;
private String phone;
private int age;
private Car car;
private List< Object> list;
private Map< String, Object> map;
}
在xml中的配置如下:
< bean id= "p10" class = "com.ddh.pojo.Person" >
< property name= "name" value= "这是第10个实验" / >
< property name= "map" >
< map>
< entry key= "key1" value= "value1" / >
< entry key= "key2" value= "value2" / >
< entry key= "key3" value= "value3" / >
< / map>
< / property>
< / bean>
测试的代码:
@Test
public void test10 ( ) throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext ( "application.xml" ) ;
Person person = ( Person) applicationContext. getBean ( "p10" ) ;
System. out. println ( person) ;
}
IOC之Properties属性的赋值
使用prop子元素为Properties类型的属性赋值
public class Person {
private int id;
private String name;
private String phone;
private int age;
private Car car;
private List< Object> list;
private Map< String, Object> map;
private Properties prop;
}
xml中的配置如下:
< bean id= "p11" class = "com.ddh.pojo.Person" >
< property name= "name" value= "这是第10个实验" / >
< property name= "prop" >
< props>
< prop key= "jdbc.url" > jdbc: mysql: / / localhost: 3306 / test< / prop>
< prop key= "jdbc.password" > root< / prop>
< / props>
< / property>
< / bean>
测试的代码:
@Test
public void test11 ( ) throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext ( "application.xml" ) ;
Person person = ( Person) applicationContext. getBean ( "p11" ) ;
System. out. println ( person) ;
}
IOC之util 名称空间
util名称空间,可以定义
实验13 :通过util名称空间创建集合类型的bean
在xml中的配置:
< ! -- util: list定义一个list集合 -- >
< util: list id= "list1" >
< list>
< value> list1< / value>
< value> list2< / value>
< value> list3< / value>
< / list>
< / util: list>
< bean id= "p12" class = "com.ddh.pojo.Person" >
< property name= "name" value= "这是12个Person" / >
< property name= "list" ref= "list1" / >
< / bean>
测试的代码:
@Test
public void test12 ( ) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext ( "application.xml" ) ;
Person person = ( Person) applicationContext. getBean ( "p12" ) ;
System. out. println ( person) ;
System. out. println ( applicationContext. getBean ( "list1" ) ) ;
}
IOC之级联属性赋值
给bean的级联属性赋值
在xml中的配置:
< bean id= "p13" class = "com.ddh.pojo.Person" >
< property name= "name" value= "这是12个Person" / >
< ! -- 先赋值 -- >
< property name= "car" ref= "car1" > < / property>
< ! -- 再级联修改属性 -- >
< property name= "car.id" value= "2" / >
< property name= "car.name" value= "级联属性赋值" / >
< / bean>
测试的代码:
@Test
public void test13 ( ) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext ( "application.xml" ) ;
Person person = ( Person) applicationContext. getBean ( "p13" ) ;
System. out. println ( person) ;
}
常见错误:级联属性一定要先注入对象。再注入对象的属性
IOC之静态工厂方法创建Bean
配置通过静态工厂方法创建的bean
1 、创建一个工厂类
public class PersonFactory {
public static Person createPerson ( ) {
Person person = new Person ( ) ;
person. setName ( "这是通过静态工厂方法创建的Person对象" ) ;
return person;
}
}
2 、到xml中去配置:
< ! --
id 还是bean的唯一标识
class 属性定义工厂类全类名
factory- method 属性是调用哪个方法,的方法名
-- >
< bean id= "p14" class = "com.ddh.util.PersonFactory" factory- method= "createPerson" / >
测试的代码:
@Test
public void test14 ( ) throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext ( "application.xml" ) ;
Person person = ( Person) applicationContext. getBean ( "p14" ) ;
System. out. println ( person) ;
}
IOC之工厂实例方法创建Bean
配置通过实例工厂方法创建的bean
public class PersonFactory {
public static Person createPerson ( ) {
Person person = new Person ( ) ;
person. setName ( "这是通过静态工厂方法创建的Person对象" ) ;
return person;
}
public Person createPerson2 ( ) {
Person person = new Person ( ) ;
person. setName ( "这是通过工厂实例对象创建的Person" ) ;
return person;
}
}
在xml中的配置:
< bean id= "personFactory" class = "com.ddh.util.PersonFactory" / >
< ! --
id是唯一的标识
factory- bean 引用哪个工厂对象的实例
factory- method 同时是调用哪个方法,的方法名
-- >
< bean id= "p15" factory- bean= "personFactory" factory- method= "createPerson2" / >
测试的代码:
@Test
public void test15 ( ) throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext ( "application.xml" ) ;
Person person = ( Person) applicationContext. getBean ( "p15" ) ;
System. out. println ( person) ;
}
IOC之FactoryBean接口方式创建对象
配置FactoryBean接口创建Bean对象
1 、实现FactoryBean接口
public class PersonFactoryBean implements FactoryBean < Person> {
@Override
public Person getObject ( ) throws Exception {
Person person = new Person ( ) ;
person. setName ( "这是FactoryBean接口的方式创建的" ) ;
return person;
}
@Override
public Class< ? > getObjectType ( ) {
return Person. class ;
}
@Override
public boolean isSingleton ( ) {
return true ;
}
}
3 、在xml配置文件中的配置:
< bean id= "p16" class = "com.ddh.util.PersonFactoryBean" / >
测试的代码:
@Test
public void test16 ( ) throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext ( "application.xml" ) ;
Person person = ( Person) applicationContext. getBean ( "p16" ) ;
System. out. println ( person) ;
}
IOC之继承Bean配置
通过继承实现bean配置信息的重用
xml配置文件中的内容:
< ! -- bean标签用于配置一个组件对象(javaBean,Dao。Service)
id 是给bean对象起一个唯一的标识
class bean 对象的具体全类名
-- >
< bean id= "p1" class = "com.ddh.pojo.Person" >
< ! -- property标签用来配置属性信息
name 是属性名
value 是属性值
-- >
< property name= "id" value= "1" / >
< property name= "name" value= "华仔" / >
< property name= "age" value= "18" / >
< property name= "phone" value= "18699998888" / >
< / bean>
< ! --
parent 设置你继承哪个bean的信息
-- >
< bean id= "p17" class = "com.ddh.pojo.Person" parent= "p1" >
< property name= "list" >
< list>
< value> 这是继承的1 < / value>
< value> 这是继承的2 < / value>
< / list>
< / property>
< / bean>
测试的代码:
@Test
public void test17 ( ) throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext ( "application.xml" ) ;
Person person = ( Person) applicationContext. getBean ( "p17" ) ;
System. out. println ( person) ;
}
IOC之abstract抽象Bean
通过abstract 属性创建一个模板bean
xml中的配置:
< ! -- bean标签用于配置一个组件对象(javaBean,Dao。Service)
id 是给bean对象起一个唯一的标识
class bean 对象的具体全类名
表示当前bean标签所配置的bean对象,不能实例化
-- >
< bean id= "p1" class = "com.ddh.pojo.Person" abstract = "true" >
< ! -- property标签用来配置属性信息
name 是属性名
value 是属性值
-- >
< property name= "id" value= "1" / >
< property name= "name" value= "华仔" / >
< property name= "age" value= "18" / >
< property name= "phone" value= "18699998888" / >
< / bean>
如果配置的bean标签对象,设置了属性abstract = "true" ,那么此标签中的对象不能实例化
IOC之组件创建顺序
bean之间的依赖 depends- on 属性
< ? 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" >
< ! -- depends- on= "b" 如果要创建a对象,就要有b对象
也就是要先创建b再创建a
-- >
< bean id= "a" class = "com.ddh.pojo.A" depends- on= "b" > < / bean>
< bean id= "b" class = "com.ddh.pojo.B" > < / bean>
< bean id= "c" class = "com.ddh.pojo.C" > < / bean>
< / beans>
测试的代码:
@Test
public void test20 ( ) throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext ( "application2.xml" ) ;
}
IOC之Bean的单例和多例(重要)
测试bean的作用域,分别创建单实例和多实例的bean★
< ! --
scope 属性设置范围
singleton 默认情况 是singleton,表示Spring容器中只有一个单例
单例是在Spring容器创建的时候。初始化所有单例Bean对象
并且每次调用Bean对象的时候,原来原来Spring容器中的对象
prototype prototype是表示当前配置的Bean对象是多例。
在Spring容器被创建的时候,bean不会被创建出来。
并且每次调用getBean方法都会创建一个对象实例
request 表示一次请求内,不管调用几次getBean方法,返回的都是同一个bean对象
Object bean = request. getAttribute ( xxx) ;
if ( bean == null) {
bean = 创建一个
request. setAttribute ( xxx, bean) ;
}
session 表示一个Session对象内,不管调用几次getBean方法,返回的都同一个Bean对象
Object bean = session. getAttribute ( xxx) ;
if ( bean == null) {
bean = 创建一个
session. setAttribute ( xxx, bean) ;
}
-- >
< bean id= "p21" class = "com.ddh.pojo.Person" scope= "prototype" >
< property name= "id" value= "1" / >
< property name= "name" value= "华仔" / >
< property name= "age" value= "18" / >
< property name= "phone" value= "18699998888" / >
< / bean>
基于xml配置文件的自动注入
先创建Person类和Car类
public class Car {
private int id;
private String name;
public class Person {
private Car car;
public Person ( Car car) {
this . car = car;
}
xml中的配置如下:
< bean id= "car" class = "com.ddh.pojo.Car" >
< property name= "id" value= "1" / >
< property name= "name" value= "宝马1" / >
< / bean>
< bean id= "car1" class = "com.ddh.pojo.Car" >
< property name= "id" value= "2" / >
< property name= "name" value= "宝马2" / >
< / bean>
< ! --
autowire 设置自动装配的方式
default 和 no一样,都表示不装配,如果对象不你手动设置,就没值。
byName 表示Spring容器会自动按照子对象的属性名,当成是id来查找对象。
找到就注入,找不到就为null
举例:private Car car;
就会以car做为id去spring容器中去查找对象。找到就把值注入给属性car。
byType 表示Spring容器会自动的按照子对象的类型去查找bean对象注入。
举例:private Car car;
Spring容器就会自动的按照Car. class 类型去Spring容器中查找。
如果说,找到一个,就注入
如果没有找到,值就为null
如果说,找到多个,就报错。
constructor 表示Spring容器会按照子对象的类型去查找构造方法,中参数需要的类型去注入。
先按照类型查询,如果找到一个就注入。
如果找到多个,再按照构造方法中参数的变量名做为id来查找,如果找到就注入。如果没有找到,就为null
如果没有找到,值也为null
-- >
< bean id= "p22" class = "com.ddh.pojo.Person" autowire= "constructor" >
< property name= "id" value= "1" / >
< property name= "name" value= "华仔" / >
< property name= "age" value= "18" / >
< property name= "phone" value= "18699998888" / >
< / bean>
对象的生命周期
IOC之Bean的生命周期
创建带有生命周期方法的bean
给A类添加生命周期方法:
public class A {
public A ( ) {
System. out. println ( "这是A对象被创建了" ) ;
}
public void initA ( ) {
System. out. println ( "这里是初始化A的方法" ) ;
}
public void destroyA ( ) {
System. out. println ( "这里是销毁A的方法" ) ;
}
}
在xml配置文件中配置如下:
< ! --
init- method= "initA" 设置初始化方法
destroy- method= "destroyA" 设置销毁的方法
-- >
< bean id= "a" class = "com.ddh.pojo.A" init- method= "initA" destroy- method= "destroyA" > < / bean>
测试的代码:
@Test
public void test23 ( ) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext ( "application2.xml" ) ;
applicationContext. close ( ) ;
}
Bean的后置处理器BeanPostProcessor
测试bean的后置处理器
创建一个AI接口
public interface AI {
public void show ( ) ;
}
修改A类实现AI接口
public class A implements AI {
public A ( ) {
System. out. println ( "这是A对象被创建了" ) ;
}
public void initA ( ) {
System. out. println ( "这里是初始化A的方法" ) ;
}
public void destroyA ( ) {
System. out. println ( "这里是销毁A的方法" ) ;
}
@Override
public void show ( ) {
System. out. println ( "--这是目标A对象的show方法--" ) ;
}
}
1 、创建一个类去实现后置处理器的接口
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization ( Object bean, String beanName)
throws BeansException {
System. out. println ( "这是初始化之前: bean->[" + bean + "] , beanName ->["
+ beanName + "]" ) ;
return bean;
}
@Override
public Object postProcessAfterInitialization ( Object bean, String beanName)
throws BeansException {
System. out. println ( "这是初始化之后: bean->[" + bean + "] , beanName ->["
+ beanName + "]" ) ;
if ( "a" . equals ( beanName) ) {
AI proxyAi = ( AI) Proxy. newProxyInstance ( bean. getClass ( )
. getClassLoader ( ) , bean. getClass ( ) . getInterfaces ( ) ,
new InvocationHandler ( ) {
@Override
public Object invoke ( Object proxy, Method method,
Object[ ] args) throws Throwable {
System. out. println ( "这是前置增强代码" ) ;
Object result = method. invoke ( bean, args) ;
System. out. println ( "这是后置增强代码" ) ;
return result;
}
} ) ;
return proxyAi;
} else {
return bean;
}
}
}
2 、到Spring的配置文件中去配置后置处理器
< ! --
init- method= "initA" 设置初始化方法
destroy- method= "destroyA" 设置销毁的方法
-- >
< bean id= "a" class = "com.ddh.pojo.A" init- method= "initA" destroy- method= "destroyA" > < / bean>
< ! -- 配置Bean的后配置处理器。 -- >
< bean class = "com.ddh.util.MyBeanPostProcessor" / >
测试的代码:
@Test
public void test24 ( ) {
@SuppressWarnings ( "resource" )
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext (
"application2.xml" ) ;
AI ai = ( AI) applicationContext. getBean ( "a" ) ;
ai. show ( ) ;
}
6、Spring管理数据库连接池(重要)
再次搭建Spring的开发环境:
1 、创建一个Java工程
2 、导入Spring需要的jar包
commons- logging- 1.1 .3 . jar
spring- beans- 4.0 .0 . RELEASE. jar
spring- context- 4.0 .0 . RELEASE. jar
spring- core- 4.0 .0 . RELEASE. jar
spring- expression- 4.0 .0 . RELEASE. jar
3 、还有日记包
log4j- 1.2 .17 . jar
4 、log4j. properties属性配置文件
# Global logging configuration
log4j. rootLogger= INFO, stdout
# Console output. . .
log4j. appender. stdout= org. apache. log4j. ConsoleAppender
log4j. appender. stdout. layout= org. apache. log4j. PatternLayout
log4j. appender. stdout. layout. ConversionPattern= % 5 p [ % t] - % m% n
5 、还需要导入数据库驱动包以及数据库连接池
c3p0- 0.9 .1 .2 . jar
mysql- connector- java- 5.1 .37 - bin. jar
6 、创建Spring的配置文件application. xml
Spring引入单独的jdbc.properties配置文件(重点)
1 、抽取四个jdbc连接属性到jdbc. properties属性配置文件中
jdbc. username= root
jdbc. password= root
jdbc. url= jdbc: mysql: / / localhost: 3306 / ddh
jdbc. driverClassName= com. mysql. jdbc. Driver
2 、使用PropertyPlaceholderConfigurer 来加载jdbc. properties属性配置文件
< ! -- 它可以加载jdbc. properties属性配置文件 -- >
< bean class = "org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" >
< ! -- location 属性是你要加载的jdbc. properties属性配置文件的路径 -- >
< property name= "location" value= "classpath:jdbc.properties" / >
< / bean>
3 、使用加载后的jdbc. properties属性配置文件中的连接属性。
< ! -- 配置一个数据库连接池对象 -- >
< bean id= "dataSource" class = "com.alibaba.druid.pool.DruidDataSource" >
< property name= "url " value= "${jdbc.url}" / >
< property name= "username" value= "${jdbc.user}" / >
< property name= "password" value= "${jdbc.password}" / >
< property name= "driverClassName" value= "${jdbc.driverClass}" / >
< / bean>
使用context名称空间加载jdbc.properties配置文件(重点)
< ! -- 也可以加载classpath路径下的jdbc. properties属性配置文件 -- >
< context: property- placeholder location= "classpath:jdbc.properties" / >
Spring EL表达式
创建java实体Bean对象
public class Person {
private int id;
private String name;
private String phone;
private double salary;
private Car car;
}
public class Car {
private String name;
private String carNo;
}
实验26 :[ SpEL测试I] 在SpEL中使用字面量
使用格式:#{ 数值} #{ “字符串” || ‘字符串’}
实验27 :[ SpEL测试II] 在SpEL中引用其他bean
使用格式:#{ bean的id}
实验28 :[ SpEL测试III] 在SpEL中引用其他bean的某个属性值
使用格式: #{ bean. 属性名}
实验29 :[ SpEL测试IV] 在SpEL中调用非静态方法
使用格式: #{ bean. 方法名( 参数) }
实验30 :[ SpEL测试V] 在SpEL中调用静态方法
使用格式:#{ T ( 全名类) . 方法名( 参数) }
实验31 :[ SpEL测试VI] 在SpEL中使用运算符
使用格式:#{ 表达式}
< bean id= "car" class = "com.ddh.pojo.Car" >
< property name= "name" value= "宝马" / >
< property name= "carNo" value= "京B123421" / >
< / bean>
< bean id= "personEL" class = "com.ddh.pojo.Person" >
< ! -- 实验26 :[ SpEL测试I] 在SpEL中使用字面量 -- >
< ! -- 使用格式:#{ 数值} #{ “字符串” || ‘字符串’} -- >
< ! -- < property name= "name" value= "#{'这是EL表达式常量值'}" / > -- >
< ! -- 实验27 :[ SpEL测试II] 在SpEL中引用其他bean -- >
< ! -- 使用格式:#{ bean的id} -- >
< property name= "car" value= "#{car}" / >
< ! -- 实验28 :[ SpEL测试III] 在SpEL中引用其他bean的某个属性值 -- >
< ! -- 使用格式: #{ bean. 属性名} -- >
< property name= "phone" value= "#{car.name}" / >
< ! -- 实验29 :[ SpEL测试IV] 在SpEL中调用非静态方法 -- >
< ! -- 使用格式: #{ bean. 方法名( 参数) } -- >
< ! -- < property name= "name" value= "#{car.fun1()}" / > -- >
< ! -- 实验30 :[ SpEL测试V] 在SpEL中调用静态方法 -- >
< ! -- 使用格式:#{ T ( 全名类) . 方法名( 参数) } -- >
< property name= "name" value= "#{T(com.ddh.pojo.Car).staticFun()}" / >
< ! -- 实验31 :[ SpEL测试VI] 在SpEL中使用运算符 -- >
< ! -- 使用格式:#{ 表达式} -- >
< property name= "salary" value= "#{10*1024}" / >
< / bean>
注解配置Dao、Service、Controller组件
当我们使用Spring的注解功能的时候。需要把aop的jar包导入
通过注解分别创建Dao、Service、Controller★
Spring配置bean的常用注解有
@Controller 专门标注给web层的组件
@Service 专门给Service层的组件注解
@Repository 给Dao层组件标注
@Component 给Dao、Service、控制器Web层之外的组件进行标注。
@Scope 可以修改bean的Scope属性,默认不标注此注解表示单例。
也可以通过注解修改为多例@Scope ( value= "prototype" )
注解在类上的使用:
@Scope ( value= "prototype" )
@Repository ( value= "bookDao" )
public class BookDao {
public BookDao ( ) {
System. out. println ( "BookDao也被初始化了" ) ;
}
}
当我们在类上使用了注解之后。一定要在Spring配置文件中加上包扫描的配置才能生效
< ! -- context: component- scan 表示包扫描
base- package 指定要扫描哪些包下的类(并且包含子包)
-- >
< context: component- scan base- package = "com.ddh" > < / context: component- scan>
测试代码:
@Test
public void test1 ( ) throws Exception {
@SuppressWarnings ( "resource" )
ApplicationContext applicationContext = new ClassPathXmlApplicationContext ( "application.xml" ) ;
System. out. println ( applicationContext. getBean ( "bookDao" ) ) ;
System. out. println ( applicationContext. getBean ( "bookDao" ) ) ;
System. out. println ( applicationContext. getBean ( "bookDao" ) ) ;
System. out. println ( applicationContext. getBean ( "bookService" ) ) ;
System. out. println ( applicationContext. getBean ( "bookServlet" ) ) ;
System. out. println ( applicationContext. getBean ( "person" ) ) ;
}
指定扫描包时的过滤内容(重要)
使用context: include- filter指定扫描包时要包含的类
使用context: exclude- filter指定扫描包时不包含的类
< context: include- filter / > 设置包含的内容
注意:通常需要与use- default - filters属性配合使用才能够达到“仅包含某些组件”这样的效果。即:通过将use- default - filters属性设置为false ,
< context: exclude- filter / > 设置排除的内容
类别 示例 说明
annotation com. ddh. XxxAnnotation 过滤所有标注了XxxAnnotation的类。这个规则根据目标组件是否标注了指定类型的注解进行过滤
assignable com. ddh. BaseXxx 过滤所有BaseXxx类的子类。这个规则根据目标组件是否是指定类型的子类的方式进行过滤。
aspectj com. ddh. *Service+ 所有类名是以Service结束的,或这样的类的子类。这个规则根据AspectJ表达式进行过滤。
regex com\. ddh\. anno\. * 所有com. ddh. anno包下的类。这个规则根据正则表达式匹配到的类名进行过滤。
custom com. ddh. XxxTypeFilter 使用XxxTypeFilter类通过编码的方式自定义过滤规则。该类必须实现org. springframework. core. type. filter. TypeFilter接口
applicationContext. xml 中配置的内容如下
< ! -- use- default - filters= "false" 设置取消默认包含规则 -- >
< context: component- scan base- package = "com.ddh" use- default - filters= "false" >
< ! -- context: include- filter 设置包含的内容 -- >
< context: include- filter type= "annotation" expression= "org.springframework.stereotype.Service" / >
< ! -- context: exclude- filter 设置排除的内容 -- >
< context: exclude- filter type= "assignable" expression= "com.ddh.service.BookService" / >
< / context: component- scan>
以上配置会包含所有@Service 注解的类。排除com. ddh. service. BookService类
使用注解@Autowired自动装配
使用@Autowired 注解实现根据类型实现自动装配★
@Autowired 注解 会自动的根据标注的对象类型在Spring容器中查找相对应的类。找到就自动装配。
使用@Autowired 注解,不需要get/ set方法
@Repository
public class BookDao {
public BookDao ( ) {
System. out. println ( "BookDao也被初始化了" ) ;
}
}
@Service ( "bookService" )
public class BookService {
public BookService ( ) {
System. out. println ( "bookService被初始化了" ) ;
}
@Autowired
private BookDao bookDao;
@Override
public String toString ( ) {
return "BookService [bookDao=" + bookDao + "]" ;
}
}
多个同类型的bean如何自动装配
如果资源类型的bean不止一个,默认根据@Autowired 注解标记的成员变量名作为id查找bean,进行装配
@Repository
public class BookDao {
public BookDao ( ) {
System. out. println ( "BookDao也被初始化了" ) ;
}
}
@Repository
public class BookDaoExt extends BookDao {
public BookDaoExt ( ) {
System. out. println ( "BookDaoExt也被初始化了" ) ;
}
}
@Service ( "bookService" )
public class BookService {
public BookService ( ) {
System. out. println ( "bookService被初始化了" ) ;
}
@Autowired
private BookDao bookDao;
@Override
public String toString ( ) {
return "BookService [bookDao=" + bookDao + "]" ;
}
}
使用@Qualifier装配指定id的bean对象
如果根据成员变量名作为id还是找不到bean,可以使用@Qualifier 注解明确指定目标bean的id★
@Repository ( value= "aaa" )
public class BookDao {
public BookDao ( ) {
System. out. println ( "BookDao也被初始化了" ) ;
}
}
@Repository ( value= "bbb" )
public class BookDaoExt extends BookDao {
public BookDaoExt ( ) {
System. out. println ( "BookDaoExt也被初始化了" ) ;
}
}
@Autowired
@Qualifier ( "bbb" )
private BookDao bookDao;
@Autowired注解的required属性作用
@Autowired 注解的required属性作用
实验39 :@Autowired 注解的required属性指定某个属性允许不被设置
@Autowired ( required= false )
@Qualifier ( "ccc" )
private BookDao bookDao;
@Autowired和@Qualifier在方法上的使用
在方法的形参位置使用@Qualifier 注解
private BookDao bookDaoExt;
@Autowired
public void abc ( @Qualifier ( value = "aaa" ) BookDao bookDao) {
System. out. println ( "这是被标注了@Autowired注解的方法…………" ) ;
System. out. println ( bookDao) ;
this . bookDaoExt = bookDao;
}
泛型注入
测试泛型依赖注入★
所有的Dao代码:
public abstract class BaseDao < T> {
public abstract void save ( T entity) ;
}
@Repository
public class BookDao extends BaseDao < Book> {
@Override
public void save ( Book entity) {
System. out. println ( "这是BookDao,保存一个Book --->>>" + entity) ;
}
}
@Repository
public class UserDao extends BaseDao < User> {
@Override
public void save ( User entity) {
System. out. println ( "这是UserDao,保存一个User --->>>" + entity) ;
}
}
所有的Service代码:
public abstract class BaseService < T> {
@Autowired
protected BaseDao< T> dao;
public void save ( T entity) {
dao. save ( entity) ;
}
}
@Service
public class BookService extends BaseService < Book> {
}
@Service
public class UserService extends BaseService < User> {
}
Spring的配置文件内容:
< ? xml version= "1.0" encoding= "UTF-8" ? >
< beans xmlns= "http://www.springframework.org/schema/beans"
xmlns: xsi= "http://www.w3.org/2001/XMLSchema-instance"
xmlns: context= "http://www.springframework.org/schema/context"
xsi: schemaLocation= "http: / / www. springframework. org/ schema/ beans http: / / www. springframework. org/ schema/ beans/ spring- beans. xsd
http: / / www. springframework. org/ schema/ context http: / / www. springframework. org/ schema/ context/ spring- context- 4.0 . xsd">
< ! -- 扫描全部的包 -- >
< context: component- scan base- package = "com.ddh" > < / context: component- scan>
< / beans>
测试的代码:
public class SpringTest {
@Test
public void test1 ( ) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext ( "application.xml" ) ;
BookService bookService = ( BookService) applicationContext. getBean ( "bookService" ) ;
bookService. save ( new Book ( ) ) ;
UserService userService = ( UserService) applicationContext. getBean ( "userService" ) ;
userService. save ( new User ( ) ) ;
}
}
Spring的专有测试
先导入spring- test- 4.0 .0 . RELEASE. jar包
@ContextConfiguration ( locations = "classpath:application.xml" )
@RunWith ( SpringJUnit4ClassRunner. class )
public class SpringJunit {
@Autowired
private BookService bookService;
@Autowired
private UserService userService;
@Autowired
private UserDao userDao;
@Test
public void test1 ( ) {
bookService. save ( new Book ( ) ) ;
userService. save ( new User ( ) ) ;
System. out. println ( userDao) ;
}
}
AOP切面编程
什么是AOP
AOP是面向切面编程。全称:Aspect Oriented Programming
面向切面编程指的是:程序是运行期间,动态地将某段代码插入到原来方法代码的某些位置中。这就叫面向切面编程。
一个简单计算数功能加日记
准备计算器相关类
计算接口
public interface Calculate {
public int add ( int num1, int num2) ;
public int mul ( int num1, int num2) ;
public int div ( int num1, int num2) ;
public int sub ( int num1, int num2) ;
}
计算机类
public class Calculator implements Calculate {
public int add ( int num1, int num2) {
System. out. println ( "日记 :【add】 方法调用前 。参数1是:" + num1 + " , 参数2是:" + num2) ;
return num1 + num2;
}
public int mul ( int num1, int num2) {
System. out. println ( "日记 :【mul】 方法调用前 。参数1是:" + num1 + " , 参数2是:" + num2) ;
return num1 * num2;
}
public int div ( int num1, int num2) {
System. out. println ( "日记 :【div】 方法调用前 。参数1是:" + num1 + " , 参数2是:" + num2) ;
return num1 / num2;
}
public int sub ( int num1, int num2) {
System. out. println ( "日记 :【sub】 方法调用前 。参数1是:" + num1 + " , 参数2是:" + num2) ;
return num1 - num2;
}
}
测试的代码
public class CalculatorTest {
public static void main ( String[ ] args) {
Calculate calculate = new Calculator ( ) ;
int result = calculate. add ( 12 , 12 ) ;
System. out. println ( "相加的结果:" + result) ;
result = calculate. mul ( 12 , 12 ) ;
System. out. println ( "相乘的结果:" + result) ;
}
}
上面这种方法加日记处理操作。日记的代码就会耦合到业务代码中。而且后期如果需要修改日记就需要去指的修改所有方法中的日记操作。这个维护操作非常不方便。
可以说是一个很失败的例子。
原始方法统一日记处理
把日记的内容封装到一个类去中集中处理。
编写一个日记处理工具类
public class LogUtil {
public static void log ( String method, int num1, int num2) {
System. out. println ( "日记 :【" + method + "】 方法调用前 。参数1是:" + num1 + " , 参数2是:" + num2) ;
}
}
修改原来Calculator中的日记代码
@Override
public int add ( int num1, int num2) {
LogUtil. log ( "add" , num1, num2) ;
return num1 + num2;
}
@Override
public int mul ( int num1, int num2) {
LogUtil. log ( "mul" , num1, num2) ;
return num1 * num2;
}
但是这种方式的不足之处是,每有一个需要加日记的类,都需要到类的代码中去添加日记功能代码。
无法做到所有对象都统一处理。
使用代理实现日记
使用jdk动态代理统一日记
创建一个计算器代理工具类
public class CalculateProxyFactory {
public static Calculate getProxy ( Calculate target) {
class CalculateInvocationHandler implements InvocationHandler {
Calculate target;
public CalculateInvocationHandler ( Calculate calculate) {
this . target = calculate;
}
@Override
public Object invoke ( Object proxy, Method method, Object[ ] args) throws Throwable {
if ( method. getDeclaringClass ( ) . equals ( Object. class ) ) {
return method. invoke ( target, args) ;
}
LogUtil. log ( method. getName ( ) , ( int ) args[ 0 ] , ( int ) args[ 1 ] ) ;
Object result = null;
try {
result = method. invoke ( target, args) ;
System. out. println ( "后置日记" ) ;
} catch ( Exception e) {
System. out. println ( "异常日记" ) ;
} finally {
System. out. println ( "finally日记" ) ;
}
return result;
}
}
return ( Calculate) Proxy. newProxyInstance ( target. getClass ( ) . getClassLoader ( ) , target. getClass ( )
. getInterfaces ( ) , new CalculateInvocationHandler ( target) ) ;
}
}
修改原来计算器中的日记代码
public class Calculator implements Calculate {
@Override
public int add ( int num1, int num2) {
return num1 + num2;
}
@Override
public int mul ( int num1, int num2) {
return num1 * num2;
}
@Override
public int div ( int num1, int num2) {
return num1 / num2;
}
@Override
public int sub ( int num1, int num2) {
return num1 - num2;
}
}
测试代码调整
public static void main ( String[ ] args) {
Calculate calculate = CalculateProxyFactory. getProxy ( new Calculator ( ) ) ;
int result = calculate. add ( 12 , 12 ) ;
System. out. println ( "相加的结果:" + result) ;
result = calculate. mul ( 12 , 12 ) ;
System. out. println ( "相乘的结果:" + result) ;
}
优点:这种方式已经解决我们前面所有日记需要的问题。非常的灵活。而且可以方便的在后期进行维护和升级。
缺点:当然使用jdk动态代理,需要有接口。如果没有接口。就无法使用jdk动态代理。
使用cglib代理
public class CGLibProxyFactory implements MethodInterceptor {
public static Object getCGLibProxy ( Object target, Callback callback) {
Enhancer enhancer = new Enhancer ( ) ;
enhancer. setSuperclass ( target. getClass ( ) ) ;
enhancer. setCallback ( callback) ;
return enhancer. create ( ) ;
}
@Override
public Object intercept ( Object proxy, Method method, Object[ ] params, MethodProxy methodProxy)
throws Throwable {
LogUtil. log ( method. getName ( ) , ( int ) params[ 0 ] , ( int ) params[ 1 ] ) ;
Object result = methodProxy. invokeSuper ( proxy, params) ;
System. out. println ( "这是后置代码" ) ;
return result;
}
public static void main ( String[ ] args) {
Calculator calculator = ( Calculator) CGLibProxyFactory. getCGLibProxy ( new Calculator ( ) ,
new CGLibProxyFactory ( ) ) ;
calculator. add ( 12 , 13 ) ;
}
}
优点:在没有接口的情况下,同样可以实现代理的效果。
缺点:同样需要自己编码实现代理全部过程。
但是为了更好的整合Spring框架使用。所以我们需要学习一下Spring 的AOP 功能。也就是学习Spring提供的AOP功能。
AOP编程的专业术语
通知(Advice)
通知就是增强的代码。比如前置增强的代码。后置增强的代码。异常增强代码。返回结果通知代码。这些就叫通知
切面(Aspect)
切面就是包含有通知代码的类叫切面。
横切关注点
横切关注点,就是我们可以添加增强代码的位置。比如前置位置,后置位置,异常位置。和返回值位置。这些都叫横切关注点。
目标(Target)
目标对象就是被关注的对象。或者被代理的对象。
代理(Proxy)
为了拦截目标对象方法,而被创建出来的那个对象,就叫做代理对象。
连接点(Joinpoint)
连接点指的是横切关注点和程序代码的连接,叫连接点。
切入点(pointcut)
切入点指的是用户真正处理的连接点,叫切入点。
在Spring中切入点通过org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件。
使用Spring实现AOP简单切面编程
需要导入工程的jar包
Spring的核心包
spring- beans- 4.0 .0 . RELEASE. jar
spring- context- 4.0 .0 . RELEASE. jar
spring- core- 4.0 .0 . RELEASE. jar
spring- expression- 4.0 .0 . RELEASE. jar
Spring的测试包
spring- test- 4.0 .0 . RELEASE. jar
Spring日记相关包
commons- logging- 1.1 .3 . jar
log4j- 1.2 .17 . jar
Spring的AOP切面相关的包
spring- aop- 4.0 .0 . RELEASE. jar
spring- aspects- 4.0 .0 . RELEASE. jar
com. springsource. net. sf. cglib- 2.2 .0 . jar
com. springsource. org. aopalliance- 1.0 .0 . jar
com. springsource. org. aspectj. weaver- 1.6 .8 . RELEASE. jar
需要有的类
public interface Calculate {
public int add ( int num1, int num2) ;
public int mul ( int num1, int num2) ;
public int div ( int num1, int num2) ;
public int sub ( int num1, int num2) ;
}
@Component
public class Calculator implements Calculate {
@Override
public int add ( int num1, int num2) {
return num1 + num2;
}
@Override
public int mul ( int num1, int num2) {
return num1 * num2;
}
@Override
public int div ( int num1, int num2) {
return num1 / num2;
}
@Override
public int sub ( int num1, int num2) {
return num1 - num2;
}
}
@Aspect
@Component
public class LogUtil {
@Before ( value = "execution(public int com.ddh.aop.Calculator.add(int, int))" )
public static void logBefore ( ) {
System. out. println ( "前置 日记 :【xxx】 方法调用前 。参数1是:xxxx" ) ;
}
@After ( value = "execution(public int com.ddh.aop.Calculator.add(int, int))" )
public static void logAfter ( ) {
System. out. println ( "后置 日记 :【xxxx】 方法调用前 。参数1是:xxxx" ) ;
}
@AfterReturning ( value = "execution(public int com.ddh.aop.Calculator.add(int, int))" )
public static void logAfterReturn ( ) {
System. out. println ( "返回之后: 日记 :【xxxxx】 方法调用前 。参数1是:xxxxxx" ) ;
}
@AfterThrowing ( value = "execution(public int com.ddh.aop.Calculator.add(int, int))" )
public static void logThrowException ( ) {
System. out. println ( "抛异常:日记 :【xxxxx】 方法调用前 。参数1是:xxxxxx" ) ;
}
}
applicationContext. xml配置文件中的内容
< context: component- scan base- package = "com.ddh" / >
< aop: aspectj- autoproxy / >
测试代码
@ContextConfiguration ( locations = "classpath:applicationContext.xml" )
@RunWith ( SpringJUnit4ClassRunner. class )
public class SpringAopTest {
@Autowired
private Calculate calculate;
@Test
public void test1 ( ) {
System. out. println ( "添加:" + calculate. add ( 1 , 2 ) ) ;
}
}
Spring的切入点表达式
@PointCut 切入点表达式语法格式是: execution ( 访问权限 返回值类型 方法全限定名( 参数类型列表) )
限定符:
* :
1 ) 匹配某全类名下,任意或多个方法。
表示匹配com. ddh. aop. Calculator下以a打头的任意方法。并且返回值和两个参数都是int 类型。
execution ( public int com. ddh. aop. Calculator. a* ( int , int ) )
表示匹配com. ddh. aop. Calculator下的任意方法。并且返回值和两个参数都是int 类型。
execution ( public int com. ddh. aop. Calculator. *( int , int ) )
2 ) 在Spring中只有public 权限能拦截到,访问权限可以省略(访问权限不能写* )。
execution ( int com. ddh. aop. Calculator. *( int , int ) )
3 ) 匹配任意类型的返回值,可以使用 * 表示
execution ( * com. ddh. aop. Calculator. *( int , int ) )
4 ) 匹配任意子包。
execution ( * com. *. aop. Calculator. *( int , int ) )
5 ) 任意类型参数
execution ( * com. ddh. aop. Calculator. *( int , * ) )
. . :可以匹配多层路径,或任意多个任意类型参数
execution ( * com. . aop. Calculator. *( int , int ) )
execution ( * com. ddh. aop. Calculator. *( int , . . ) )
模糊匹配:
execution ( * * ( . . ) )
execution ( * * . *( . . ) )
精确匹配:
execution ( public int com. ddh. aop. Calculator. add ( int , int ) )
切入点表达式连接:&& 、||
@Before ( "execution(public int com.ddh.aop.Calculator.add(int, int))"
+ " && "
+ "execution(public * com.ddh.aop.Calculator.add(..))" )
@Before ( "execution(public int com.ddh.aop.Calculator.add(int, int))"
+ " || "
+ "execution(public * com.ddh.aop.Calculator.a*(int))" )
## Spring通知的执行顺序
```java
Spring通知的执行顺序是:
正常情况:
前置通知====>>>>后置通知=====>>>>返回值之后
异常情况:
前置通知====>>>>后置通知=====>>>>抛异常通知
测试需要的类
@Component
public class Calculator {// implements Calculate {
public int div(int num1, int num2) {
return num1 / num2;
}
public int add(int num1, int num2) {
return num1 + num2;
}
切面的类对象
@Aspect
@Component
public class LogUtil {
// 每个通知,都是同时监听加和除两个方法
@Before("execution(public int com.ddh.aop.Calculator.add(int, int))" + " || "
+ "execution(public * com.ddh.aop.Calculator.d*(..))")
public static void logBefore() {
System.out.println("前置 日记 :【xxx】 方法调用前 。参数1是:xxxx");
}
@After("execution(public int com.ddh.aop.Calculator.add(int, int))" + " || "
+ "execution(public * com.ddh.aop.Calculator.d*(..))")
public static void logAfter() {
System.out.println("后置 日记 :【xxxx】 方法调用前 。参数1是:xxxx");
}
@AfterReturning("execution(public int com.ddh.aop.Calculator.add(int, int))" + " || "
+ "execution(public * com.ddh.aop.Calculator.d*(..))")
public static void logAfterReturn() {
System.out.println("返回之后: 日记 :【xxxxx】 方法调用前 。参数1是:xxxxxx");
}
@AfterThrowing("execution(public int com.ddh.aop.Calculator.add(int, int))" + " || "
+ "execution(public * com.ddh.aop.Calculator.d*(..))")
public static void logThrowException() {
System.out.println("抛异常:日记 :【xxxxx】 方法调用前 。参数1是:xxxxxx");
}
}
测试的代码
@ContextConfiguration(locations = "classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringAopTest {
@Autowired
private Calculator calculator;
@Test
public void test1() {
//加法
calculator.add(1, 2);
System.out.println("===============================");
//减法
calculator.div(1, 0);
}
}
获取连接点信息
JoinPoint 是连接点的信息。
只需要在通知方法的参数中,加入一个JoinPoint参数。就可以获取到拦截方法的信息。
注意:是org. aspectj. lang. JoinPoint这个类。
@Aspect
@Component
public class LogUtil {
@Before ( "execution(public int com.ddh.aop.Calculator.add(int, int))" + " || "
+ "execution(public * com.ddh.aop.Calculator.d*(..))" )
public static void logBefore ( JoinPoint joinPoint) {
System. out. println ( "前置 日记 :【" + joinPoint. getSignature ( ) . getName ( ) + "】 方法调用前 。参数是:"
+ Arrays. asList ( joinPoint. getArgs ( ) ) ) ;
}
@After ( "execution(public int com.ddh.aop.Calculator.add(int, int))" + " || "
+ "execution(public * com.ddh.aop.Calculator.d*(..))" )
public static void logAfter ( JoinPoint joinPoint) {
System. out. println ( "后置 日记 :【" + joinPoint. getSignature ( ) . getName ( ) + "】 方法调用 。参数是:"
+ Arrays. asList ( joinPoint. getArgs ( ) ) ) ;
}
@AfterReturning ( "execution(public int com.ddh.aop.Calculator.add(int, int))" + " || "
+ "execution(public * com.ddh.aop.Calculator.d*(..))" )
public static void logAfterReturn ( JoinPoint joinPoint) {
System. out. println ( "返回之后: 日记 :【" + joinPoint. getSignature ( ) . getName ( ) + "】 方法调用 。参数是:"
+ Arrays. asList ( joinPoint. getArgs ( ) ) ) ;
}
@AfterThrowing ( "execution(public int com.ddh.aop.Calculator.add(int, int))" + " || "
+ "execution(public * com.ddh.aop.Calculator.d*(..))" )
public static void logThrowException ( JoinPoint joinPoint) {
System. out. println ( "抛异常:日记 :【" + joinPoint. getSignature ( ) . getName ( ) + "】 方法调用 。参数是:"
+ Arrays. asList ( joinPoint. getArgs ( ) ) ) ;
}
}
前面测试的代码没有变。再次执行的结果。都能拿到拦截的方法名和参数
获取拦截方法的返回值和抛的异常信息
获取方法返回的值分为两个步骤:
1 、在返回值通知的方法中,追加一个参数 Object result
2 、然后在@AfterReturning 注解中添加参数returning= "参数名"
获取方法抛出的异常分为两个步骤:
1 、在异常通知的方法中,追加一个参数Exception exception
2 、然后在@AfterThrowing 注解中添加参数 throwing= "参数名"
修改LogUtil切面类的代码
@AfterReturning ( value = "execution(public int com.ddh.aop.Calculator.add(int, int))"
+ " || " + "execution(public * com.ddh.aop.Calculator.d*(..))" , returning = "result" )
public static void logAfterReturn ( JoinPoint joinPoint, Object result) {
System. out. println ( "返回之后: 日记 :【" + joinPoint. getSignature ( ) . getName ( ) + "】 方法调用 。参数是:"
+ Arrays. asList ( joinPoint. getArgs ( ) ) + ",返回值:" + result) ;
}
@AfterThrowing ( value = "execution(public int com.ddh.aop.Calculator.add(int, int))"
+ " || " + "execution(public * com.ddh.aop.Calculator.d*(..))" , throwing = "exception" )
public static void logThrowException ( JoinPoint joinPoint, Exception exception) {
System. out. println ( "抛异常:日记 :【" + joinPoint. getSignature ( ) . getName ( ) + "】 方法调用 。参数是:"
+ Arrays. asList ( joinPoint. getArgs ( ) ) + ",异常对象:" + exception) ;
}
Spring的环绕通知
1 、环绕通知使用@Around 注解。
2 、环绕通知如果和其他通知同时执行。环绕通知会优先于其他通知之前执行。
3 、环绕通知一定要有返回值(环绕如果没有返回值。后面的其他通知就无法接收到目标方法执行的结果)。
4 、在环绕通知中。如果拦截异常。一定要往外抛。否则其他的异常通知是无法捕获到异常的。
在LogUtil切面类中添加环绕通知
@Around ( value = "execution(* *(..))" )
public static Object logAround ( ProceedingJoinPoint proceedingJoinPoint) {
Object[ ] args = proceedingJoinPoint. getArgs ( ) ;
Object resultObject = null;
try {
System. out. println ( "环绕前置" ) ;
resultObject = proceedingJoinPoint. proceed ( args) ;
System. out. println ( "环绕返回" ) ;
} catch ( Throwable e) {
System. out. println ( "环绕异常:" + e) ;
throw new RuntimeException ( e) ;
} finally {
System. out. println ( "环绕后置" ) ;
}
return resultObject;
}
修改测试的代码
@ContextConfiguration ( locations = "classpath:applicationContext.xml" )
@RunWith ( SpringJUnit4ClassRunner. class )
public class SpringAopTest {
@Autowired
private Calculator calculator;
@Test
public void test1 ( ) {
calculator. add ( 1 , 2 ) ;
}
}
切入点表达式的重用
切入点表达式的重点,需要分三个步骤:
1 、在切面类中定义一个空的方法
public static void pointcut1 ( ) { }
2 、在方法中使用@Pointcut 定义一个切入表达式
@Pointcut ( value= "execution(public int com.ddh.aop.Calculator.add(int, int))" + " || "
+ "execution(public * com.ddh.aop.Calculator.*(..))" )
public static void pointcut1 ( ) { }
3 、其他的通知注解中使用方法名( ) 的形式引用方法上定义的切入点表达式。
比如:@Before ( "pointcut1()" )
多个通知的执行顺序
当我们有多个切面,多个通知的时候:
1 、通知的执行顺序默认是由切面类的字母先后顺序决定。
2 、在切面类上使用@Order 注解决定通知执行的顺序(值越小,越先执行)
再添加另一个切面类
@Component
@Aspect
@Order ( 1 )
public class Validation {
@Before ( value = "com.ddh.aop.LogUtil.pointcut1()" )
public static void before ( JoinPoint joinPoint) {
System. out. println ( "这是Validation的前置通知,拦截的方法是:" + joinPoint. getSignature ( ) . getName ( ) ) ;
}
@After ( value = "com.ddh.aop.LogUtil.pointcut1()" )
public static void after ( JoinPoint joinPoint) {
System. out. println ( "这是Validation的后置通知,拦截的方法是:" + joinPoint. getSignature ( ) . getName ( ) ) ;
}
@AfterReturning ( value = "com.ddh.aop.LogUtil.pointcut1()" , returning = "result" )
public static void afterReturning ( JoinPoint joinPoint, Object result) {
System. out. println ( "这是Validation的后置通知,拦截的方法是:" + joinPoint. getSignature ( ) . getName ( )
+ ", 返回值:" + result) ;
}
}
修改原来LogUtil中的切面内容(去掉环绕通知,留下前置,后置,返回后通知)
@Aspect
@Component
@Order ( 2 )
public class LogUtil {
@Pointcut ( value= "execution(public int com.ddh.aop.Calculator.add(int, int))" + " || "
+ "execution(public * com.ddh.aop.Calculator.*(..))" )
public static void pointcut1 ( ) { }
测试的代码
@ContextConfiguration ( locations = "classpath:applicationContext.xml" )
@RunWith ( SpringJUnit4ClassRunner. class )
public class SpringAopTest {
@Autowired
private Calculator calculator;
@Test
public void test1 ( ) {
calculator. add ( 1 , 0 ) ;
}
}
如何基于xml配置aop程序
需要导入的包
com. springsource. net. sf. cglib- 2.2 .0 . jar
com. springsource. org. aopalliance- 1.0 .0 . jar
com. springsource. org. aspectj. weaver- 1.6 .8 . RELEASE. jar
commons- logging- 1.1 .3 . jar
log4j- 1.2 .17 . jar
spring- aop- 4.0 .0 . RELEASE. jar
spring- aspects- 4.0 .0 . RELEASE. jar
spring- beans- 4.0 .0 . RELEASE. jar
spring- context- 4.0 .0 . RELEASE. jar
spring- core- 4.0 .0 . RELEASE. jar
spring- expression- 4.0 .0 . RELEASE. jar
spring- test- 4.0 .0 . RELEASE. jar
工程中编写的类
public class Calculator {
public int div ( int num1, int num2) {
return num1 / num2;
}
public int add ( int num1, int num2) {
return num1 + num2;
}
}
LogUtil切面类
public class LogUtil {
public static void logBefore ( JoinPoint joinPoint) {
System. out. println ( "前置 日记 :【" + joinPoint. getSignature ( ) . getName ( ) + "】 方法调用前 。参数是:"
+ Arrays. asList ( joinPoint. getArgs ( ) ) ) ;
}
public static void logAfter ( JoinPoint joinPoint) {
System. out. println ( "后置 日记 :【" + joinPoint. getSignature ( ) . getName ( ) + "】 方法调用 。参数是:"
+ Arrays. asList ( joinPoint. getArgs ( ) ) ) ;
}
public static void logAfterReturn ( JoinPoint joinPoint, Object result) {
System. out. println ( "返回之后: 日记 :【" + joinPoint. getSignature ( ) . getName ( ) + "】 方法调用 。参数是:"
+ Arrays. asList ( joinPoint. getArgs ( ) ) + ",返回值:" + result) ;
}
public static void logThrowException ( JoinPoint joinPoint, Exception exception) {
System. out. println ( "抛异常:日记 :【" + joinPoint. getSignature ( ) . getName ( ) + "】 方法调用 。参数是:"
+ Arrays. asList ( joinPoint. getArgs ( ) ) + ",异常对象:" + exception) ;
}
}
Validation切面类
public class Validation {
public static void before ( JoinPoint joinPoint) {
System. out. println ( "这是Validation的前置通知,拦截的方法是:" + joinPoint. getSignature ( ) . getName ( ) ) ;
}
public static void after ( JoinPoint joinPoint) {
System. out. println ( "这是Validation的后置通知,拦截的方法是:" + joinPoint. getSignature ( ) . getName ( ) ) ;
}
public static void afterReturning ( JoinPoint joinPoint, Object result) {
System. out. println ( "这是Validation的后置通知,拦截的方法是:" + joinPoint. getSignature ( ) . getName ( )
+ ", 返回值:" + result) ;
}
}
ApplicationContext. xml配置文件中的内容
< ! -- 注册bean对象
添加@Component
-- >
< bean id= "calculator" class = "com.ddh.aop.Calculator" / >
< bean id= "logUtil" class = "com.ddh.aop.LogUtil" / >
< bean id= "validation" class = "com.ddh.aop.Validation" / >
< ! -- 配置AOP -- >
< aop: config>
< ! -- 定义可以共用的切入点 -- >
< aop: pointcut expression= "execution(* com.ddh.aop.Calculator.*(..))" id= "pointcut1" / >
< ! -- 定义切面类 -- >
< aop: aspect order= "1" ref= "logUtil" >
< ! -- 这是前置通知
method属性配置通知的方法
pointcut配置切入点表达式
-- >
< aop: before method= "logBefore" pointcut= "execution(* com.ddh.aop.Calculator.*(..))" / >
< aop: after method= "logAfter" pointcut= "execution(* com.ddh.aop.Calculator.*(..))" / >
< aop: after- returning method= "logAfterReturn"
returning= "result" pointcut= "execution(* com.ddh.aop.Calculator.*(..))" / >
< aop: after- throwing method= "logThrowException" throwing= "exception"
pointcut= "execution(* com.ddh.aop.Calculator.*(..))" / >
< / aop: aspect>
< ! -- 定义切面类 -- >
< aop: aspect order= "2" ref= "validation" >
< aop: before method= "before" pointcut- ref= "pointcut1" / >
< aop: after method= "after" pointcut- ref= "pointcut1" / >
< aop: after- returning method= "afterReturning"
returning= "result" pointcut- ref= "pointcut1" / >
< / aop: aspect>
< / aop: config>
测试的代码
@ContextConfiguration ( locations = "classpath:applicationContext.xml" )
@RunWith ( SpringJUnit4ClassRunner. class )
public class SpringAopTest {
@Autowired
Calculator calculator;
@Test
public void test1 ( ) {
calculator. add ( 1 , 2 ) ;
}
}
Spring之数据访问
Spring数据访问工程环境搭建
创建一个Java工程,导入需要的Jar包
Spring的核心jar包
spring- beans- 4.0 .0 . RELEASE. jar
spring- context- 4.0 .0 . RELEASE. jar
spring- core- 4.0 .0 . RELEASE. jar
spring- expression- 4.0 .0 . RELEASE. jar
Spring切面的jar包
com. springsource. net. sf. cglib- 2.2 .0 . jar
com. springsource. org. aopalliance- 1.0 .0 . jar
com. springsource. org. aspectj. weaver- 1.6 .8 . RELEASE. jar
spring- aop- 4.0 .0 . RELEASE. jar
spring- aspects- 4.0 .0 . RELEASE. jar
Spring数据访问的jar包
spring- jdbc- 4.0 .0 . RELEASE. jar
spring- orm- 4.0 .0 . RELEASE. jar
spring- tx- 4.0 .0 . RELEASE. jar
数据库访问需要的jar包
druid- 1.1 .10 . jar
mysql- connector- java- 5.1 .37 - bin. jar
日记需要的jar包
commons- logging- 1.1 .3 . jar
log4j- 1.2 .17 . jar
Spring的测试包
spring- test- 4.0 .0 . RELEASE. jar
在src目录下jdbc. properties属性配置文件
jdbc. username= root
jdbc. password= root
jdbc. url= jdbc: mysql: / / localhost: 3306 / jdbctemplate
jdbc. driverClassName= com. mysql. jdbc. Driver
在src目录下的log4j. properties配置文件
# Global logging configuration
log4j. rootLogger= INFO, stdout
# Console output. . .
log4j. appender. stdout= org. apache. log4j. ConsoleAppender
log4j. appender. stdout. layout= org. apache. log4j. PatternLayout
log4j. appender. stdout. layout. ConversionPattern= % 5 p [ % t] - % m% n
在applicationContext. xml中配置数据源
< ! -- 加载jdbc. properties配置文件 -- >
< context: property- placeholder location= "classpath:jdbc.properties" / >
< ! -- 配置数据库连接池 -- >
< bean id= "druidDataSource" class = " com.alibaba.druid.pool.DruidDataSource" >
< property name= "username" value= "${jdbc.username}" / >
< property name= "password" value= "${jdbc.password}" / >
< property name= "url" value= "${jdbc.url}" / >
< property name= "driverClassName" value= "${jdbc.driverClassName}" / >
< / bean>
< ! -- jdbcTemplate -- >
< bean id= "jdbcTemplate" class = "org.springframework.jdbc.core.JdbcTemplate" >
< property name= "dataSource" ref= "druidDataSource" / >
< / bean>
测试数据源(测试数据库连接池)
@ContextConfiguration ( locations = "classpath:applicationContext.xml" )
@RunWith ( SpringJUnit4ClassRunner. class )
public class JdbcTest {
@Autowired
DataSource dataSource;
@Test
public void test1 ( ) throws Exception {
System. out. println ( dataSource. getConnection ( ) ) ;
}
}
Spring之JdbcTemplate使用
在Spring中提供了对jdbc的封装类叫JdbcTemplate。它可以很方便的帮我们执行sql语句,操作数据库。
先准备单表的数据库数据
drop database if exists jdbctemplate;
create database jdbctemplate;
use jdbctemplate;
create table `employee` (
`id` int ( 11 ) primary key auto_increment,
`name` varchar ( 100 ) default null,
`salary` decimal ( 11 , 2 ) default null
) ;
insert into `employee`( `id`, `name`, `salary`)
values ( 1 , '张珊' , 5000.23 ) , ( 2 , '李思' , 4234.77 ) , ( 3 , '王舞' , 9034.51 ) ,
( 4 , '赵柳' , 8054.33 ) , ( 5 , '孔琪' , 6039.11 ) , ( 6 , '曹拔' , 7714.11 ) ;
select * from employee;
JdbcTemplate的使用需要在applicationContext. xml中进行配置
< ! -- jdbcTemplate -- >
< bean id= "jdbcTemplate" class = "org.springframework.jdbc.core.JdbcTemplate" >
< property name= "dataSource" ref= "druidDataSource" / >
< / bean>
实验2 :将id= 5 的记录的salary字段更新为1300.00
@Test
public void test2 ( ) throws Exception {
String sql = "update employee set salary = ? where id = ?" ;
jdbcTemplate. update ( sql, 1300 , 5 ) ;
}
实验3 :批量插入
@Test
public void test3 ( ) throws Exception {
String sql = "insert into employee(`name`,`salary`) values(?,?)" ;
ArrayList< Object[ ] > params = new ArrayList < > ( ) ;
params. add ( new Object [ ] { "aaa" , 100 } ) ;
params. add ( new Object [ ] { "bbb" , 100 } ) ;
params. add ( new Object [ ] { "ccc" , 100 } ) ;
jdbcTemplate. batchUpdate ( sql, params) ;
}
实验4 :查询id= 5 的数据库记录,封装为一个Java对象返回
创建一个Employee对象
public class Employee {
private Integer id;
private String name;
private BigDecimal salary;
@Test
public void test4 ( ) throws Exception {
String sql = "select id ,name ,salary from employee where id = ?" ;
Employee employee = jdbcTemplate. queryForObject ( sql,
new BeanPropertyRowMapper < Employee> ( Employee. class ) , 5 ) ;
System. out. println ( employee) ;
}
实验5 :查询salary> 4000 的数据库记录,封装为List集合返回
@Test
public void test5 ( ) throws Exception {
String sql = "select id,name,salary from employee where salary > ?" ;
List< Employee> list = jdbcTemplate. query ( sql, new BeanPropertyRowMapper ( Employee. class ) , 4000 ) ;
System. out. println ( list) ;
}
实验6 :查询最大salary
@Test
public void test6 ( ) throws Exception {
String sql = "select max(salary) from employee" ;
BigDecimal salary = jdbcTemplate. queryForObject ( sql, BigDecimal. class ) ;
System. out. println ( salary) ;
}
实验7 :使用带有具名参数的SQL语句插入一条员工记录,并以Map形式传入参数值
< ! -- namedParameterJdbcTemplate -- >
< bean id= "namedParameterJdbcTemplate" class = "org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate" >
< constructor- arg name= "dataSource" ref= "dataSource" / >
< / bean>
@ContextConfiguration ( locations = "classpath:applicationContext.xml" )
@RunWith ( SpringJUnit4ClassRunner. class )
public class JdbcTest {
@Autowired
DataSource dataSource;
@Autowired
JdbcTemplate jdbcTemplate;
@Autowired
NamedParameterJdbcTemplate namedParameterJdbcTemplate;
@Test
public void test7 ( ) throws Exception {
String sql = "insert into employee(`name`,`salary`) values(:name,:salary)" ;
Map< String, Object> param = new HashMap < String, Object> ( ) ;
param. put ( "name" , "小明" ) ;
param. put ( "salary" , new BigDecimal ( 55 ) ) ;
namedParameterJdbcTemplate. update ( sql, param) ;
}
实验8 :重复实验7 ,以SqlParameterSource形式传入参数值
@Test
public void test8 ( ) throws Exception {
String sql = "insert into employee(`name`,`salary`) values(:name,:salary)" ;
SqlParameterSource sqlParameterSource = new BeanPropertySqlParameterSource ( new Employee ( 0 ,
"小新" , new BigDecimal ( 11111 ) ) ) ;
namedParameterJdbcTemplate. update ( sql, sqlParameterSource) ;
}
实验9 :创建Dao,自动装配JdbcTemplate对象
添加类
@Repository
public class EmployeeDao {
@Autowired
JdbcTemplate jdbcTemplate;
public int saveEmployee ( Employee employee) {
String sql = "insert into employee(`name`,`salary`) values(?,?)" ;
return jdbcTemplate. update ( sql, employee. getName ( ) , employee. getSalary ( ) ) ;
}
}
在applicationContext. xml中配置
< ! -- 添加包扫描 -- >
< context: component- scan base- package = "com.d" / >
测试代码
@ContextConfiguration ( locations = "classpath:applicationContext.xml" )
@RunWith ( SpringJUnit4ClassRunner. class )
public class JdbcTest {
@Autowired
DataSource dataSource;
@Autowired
JdbcTemplate jdbcTemplate;
@Autowired
NamedParameterJdbcTemplate namedParameterJdbcTemplate;
@Autowired
EmployeeDao employeeDao;
@Test
public void test9 ( ) throws Exception {
employeeDao. saveEmployee ( new Employee ( null, "ssssss" , new BigDecimal ( 999 ) ) ) ;
}
实验10 :通过继承JdbcDaoSupport创建JdbcTemplate的Dao
@Repository
public class EmployeeDao extends JdbcDaoSupport {
@Autowired
protected void setDataSource2 ( DataSource dataSource) {
System. out. println ( "自动注入 + " + dataSource) ;
super . setDataSource ( dataSource) ;
}
public int saveEmployee ( Employee employee) {
String sql = "insert into employee(`name`,`salary`) values(?,?)" ;
return getJdbcTemplate ( ) . update ( sql, employee. getName ( ) , employee. getSalary ( ) ) ;
}
}
声明式事务
事务分为声明式和编程式两种:
声明式事务:声明式事务是指通过注解的形式对事务的各种特性进行控制和管理。
编码式(编程式)事务:指的是通过编码的方式实现事务的声明。
声明式事务环境搭建
准备测试数据库
##创建tx数据库
drop database if exists `tx`;
CREATE database `tx`;
##切换tx数据库
USE `tx`;
##删除用户表
DROP TABLE IF EXISTS `user`;
##创建用户表
CREATE TABLE `user` (
`id` int primary key auto_increment,
`username` varchar ( 50 ) NOT NULL,
`money` int ( 11 ) DEFAULT NULL
) ;
##插入数据
insert into `user`( `username`, `money`) values ( '张三' , 1000 ) , ( '李四' , 1000 ) ;
##删除图书表
drop table if exists `book`;
##创建图书表
create table `book`(
`id` int primary key auto_increment,
`name` varchar ( 500 ) not null,
`stock` int
) ;
##插入数据
insert into book ( `name`, `stock`) values ( 'java编程思想' , 100 ) , ( 'C++编程思想' , 100 ) ;
##查看数据
select * from book;
select * from user;
11.2 .2 、创建一个Java工程,导入Jar包
JavaBean对象
public class Book {
private Integer id;
private String name;
private int stock;
public class User {
private Integer id;
private String username;
private int money;
Dao们
@Repository
public class BookDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public int updateBook ( ) {
String sql = "update book set name = '**我被修改了!**' where id = 1" ;
return jdbcTemplate. update ( sql) ;
}
}
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public int updateUser ( ) {
String sql = "update user set username = '**我被修改了**' where id = 1" ;
return jdbcTemplate. update ( sql) ;
}
}
Service代码
@Service
public class TransactionService {
@Autowired
private UserDao userDao;
@Autowired
private BookDao bookDao;
public void updateTwoTable ( ) {
userDao. updateUser ( ) ;
bookDao. updateBook ( ) ;
}
}
测试Service的默认事务
测试service服务层的默认事务
@ContextConfiguration ( locations = "classpath:application.xml" )
@RunWith ( SpringJUnit4ClassRunner. class )
public class SpringTest {
@Autowired
private DataSource dataSource;
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private TransactionService transactionService;
@Test
public void testDataSource ( ) throws Exception {
System. out. println ( dataSource. getConnection ( ) ) ;
}
@Test
public void testJdbcTempalte ( ) throws Exception {
System. out. println ( jdbcTemplate ) ;
}
@Test
public void testTransaction ( ) throws Exception {
transactionService. updateTwoTable ( ) ;
}
}
使用Spring的注解声明事务管制
测试Spring的声明式事务
先导入AOP包,因为Spring的底层事务使用到了aop功能
com. springsource. org. aopalliance- 1.0 .0 . jar
com. springsource. org. aspectj. weaver- 1.6 .8 . RELEASE. jar
spring- aop- 4.0 .0 . RELEASE. jar
spring- aspects- 4.0 .0 . RELEASE. jar
配置Spring的事务需要的切面类DataSourceTransactionManager
< ! -- 配置DataSourceTransactionManager事务管理器== = 事务的切面类 -- >
< bean id= "transactionManager"
class = "org.springframework.jdbc.datasource.DataSourceTransactionManager" >
< property name= "dataSource" ref= "dataSource" / >
< / bean>
在Spring的配置文件中加入tx名称空间
在Spring的配置文件中
< ! -- 配置启用spring的事务注解@Transaction -- >
< tx: annotation- driven transaction- manager= "transactionManager" / >
还需要在Service的事务方法中添加@Transaction 注解
@Transactional
public void updateTwoTable ( ) {
userDao. updateUser ( ) ;
int i = 12 / 0 ;
bookDao. updateBook ( ) ;
}
noRollbackFor和noRollbackForClassName测试不回滚的异常
noRollbackFor和noRollbackForClassName测试不回滚的异常
@Transactional ( )
public void updateTwoTable ( ) {
userDao. updateUser ( ) ;
int i = 12 / 0 ;
bookDao. updateBook ( ) ;
}
自定义设置回滚异常
:rollbackFor和rollbackForClassName回滚的异常
Spring默认回滚的是RuntimeException, 运行时异常或运行时异常的子异常
@Transactional ( )
public void updateTwoTable ( ) throws FileNotFoundException {
userDao. updateUser ( ) ;
int i = 0 ;
if ( i == 0 ) {
throw new FileNotFoundException ( "sadf" ) ;
}
bookDao. updateBook ( ) ;
}
事务的只读属性
测试readOnly只读属性
@Transactional ( readOnly= true )
public void updateTwoTable ( ) throws FileNotFoundException {
userDao. updateUser ( ) ;
bookDao. updateBook ( ) ;
}
事务超时属性timeout(秒为单位)
@Transactional ( timeout= 3 )
public void updateTwoTable ( ) throws FileNotFoundException {
userDao. updateUser ( ) ;
try {
Thread. sleep ( 4000 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
bookDao. updateBook ( ) ;
}
注解演示事物传播特性
大小事务传播特性都是REQUIRED
@Transactional ( propagation = Propagation. REQUIRED)
public void multiUpdate ( ) {
@Transactional ( propagation = Propagation. REQUIRED)
public void updateBook ( ) {
@Transactional ( propagation= Propagation. REQUIRED)
public void updateUser ( ) {
实验2 :大小事务传播特性都是REQUIRES_NEW
@Transactional ( propagation = Propagation. REQUIRES_NEW)
public void multiUpdate ( )
@Transactional ( propagation = Propagation. REQUIRES_NEW)
public void updateBook ( )
@Transactional ( propagation = Propagation. REQUIRES_NEW)
public void updateUser ( )
实验3 :大事务是REQUIRED,小事务都是REQUIRES_NEW
@Transactional ( propagation = Propagation. REQUIRED)
public void multiUpdate ( )
@Transactional ( propagation = Propagation. REQUIRES_NEW)
public void updateBook ( )
@Transactional ( propagation = Propagation. REQUIRES_NEW)
public void updateUser ( )
实验4 :大事务是REQUIRED,小1 REQUIRED,小2 REQUIRES_NEW
@Transactional ( propagation = Propagation. REQUIRED)
public void multiUpdate ( )
@Transactional ( propagation = Propagation. REQUIRED)
public void updateBook ( )
@Transactional ( propagation = Propagation. REQUIRES_NEW)
public void updateUser ( )
实验5 :大事务是REQUIRED,小1 REQUIRES_NEW,小2 REQUIRED
@Transactional ( propagation = Propagation. REQUIRED)
public void multiUpdate ( )
@Transactional ( propagation = Propagation. REQUIRES_NEW)
public void updateBook ( )
@Transactional ( propagation = Propagation. REQUIRED)
public void updateUser ( )
xml配置式事务声明
去掉。所有@Transaction 的注解。
< ! -- 配置DataSourceTransactionManager事务管理器== = 事务的切面类 -- >
< bean id= "transactionManager"
class = "org.springframework.jdbc.datasource.DataSourceTransactionManager" >
< property name= "dataSource" ref= "dataSource" / >
< / bean>
< ! -- 事物特性 -- >
< tx: advice id= "tx_advice" transaction- manager= "transactionManager" >
< ! -- 配置事务特性 -- >
< tx: attributes>
< tx: method name= "multiUpdate" propagation= "REQUIRED" / >
< tx: method name= "updateBook" propagation= "REQUIRES_NEW" / >
< tx: method name= "updateUser" propagation= "REQUIRED" / >
< tx: method name= "*" read- only= "true" / >
< / tx: attributes>
< / tx: advice>
< ! -- 配置aop代理 -- >
< aop: config>
< aop: advisor advice- ref= "tx_advice" pointcut= "execution(* com.ddh.service.*Service.*(..))" / >
< / aop: config>
Spring整合Web
在web工程中添加Spring的jar包。
Spring的核心包
spring- beans- 4.0 .0 . RELEASE. jar
spring- context- 4.0 .0 . RELEASE. jar
spring- core- 4.0 .0 . RELEASE. jar
spring- expression- 4.0 .0 . RELEASE. jar
aop包
spring- aop- 4.0 .0 . RELEASE. jar
spring- aspects- 4.0 .0 . RELEASE. jar
com. springsource. org. aopalliance- 1.0 .0 . jar
com. springsource. org. aspectj. weaver- 1.6 .8 . RELEASE. jar
JDBC- ORM包
spring- jdbc- 4.0 .0 . RELEASE. jar
spring- orm- 4.0 .0 . RELEASE. jar
spring- tx- 4.0 .0 . RELEASE. jar
Spring的web整合包
spring- web- 4.0 .0 . RELEASE. jar
测试包
spring- test- 4.0 .0 . RELEASE. jar
整合Spring和Web容器分两个步骤:
1 、导入spring- web- 4.0 .0 . RELEASE. jar
2 、在web. xml配置文件中配置org. springframework. web. context. ContextLoaderListener监听器监听ServletContext的初始化
3 、在web. xml配置文件中配置contextConfigLocation上下文参数。配置Spring配置文件的位置,以用于初始化Spring容器
在web. xml中配置
< context- param>
< param- name> contextConfigLocation< / param- name>
< param- value> classpath: applicationContext. xml< / param- value>
< / context- param>
< listener>
< listener- class > org. springframework. web. context. ContextLoaderListener< / listener- class >
< / listener>
获取WebApplicationContext上下文对象的方法如下:
方法一(推荐):
WebApplicationContextUtils. getWebApplicationContext ( getServletContext ( ) )
方法二(不推荐):
getServletContext ( ) . getAttribute ( WebApplicationContext. ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) ;