前情回顾
- struts:web层,比较简单(ValueStack值栈,拦截器)
- hibernate:dao层,知识点杂
- spring:service层
基础(IOC(控制反转),DI(依赖注入))
Spring框架概述
什么是Spring
- Spring框架是一个开放源应用程序框架,是针对bean的生命周期进行管理的轻量级容器(lightweight container)。 Spring解决了开发者在J2EE开发中遇到的许多常见的问题,提供了功能强大IOC、AOP及Web MVC等功能。Spring可以单独应用于构筑应用程序,也可以和Struts、Webwork、Tapestry等众多Web框架组合使用,并且可以与 Swing等桌面应用程序AP组合。因此, Spring不仅仅能应用于JEE应用程序之中,也可以应用于桌面应用程序以及小应用程序之中。Spring框架主要由七部分组成,分别是 Spring Core、 Spring AOP、 Spring ORM、 Spring DAO、Spring Context、 Spring Web和 Spring Web MVC。
- 轻量级:与EJB对比,依赖资源少,销毁的资源少。
- 分层
- web层:struts,spring-MVC
- service层:spring
- dao层:hibernate,mybatis,jdbcTemplate
spring核心
Spring的核心是___控制反转__(IOC)和__面向切面__(AOP)
spring优点
- 方便解耦,简化开发(高内聚,低耦合)
- spring就是工厂(容器)
- 用于生成bean
- AOP编程的支持
- 声明式事务的支持
- 方便程序的测试
- 方便集成各种优秀框架
- 降低JavaEEAPI的使用难度
spring体系结构
Beans:管理bean
Core:核心
Context:上下文(配置文件)
Expression:spel表达式
AOP:切面编程
Aspects:AOP框架
JDBC:JdbcTemplete,数据库开发
ORM:整合hibernate
Transactions:事务管理
Web:web开发
Struts:整合struts
Test:整合Junit
IOC入门,控制反转
构建maven依赖
<!-- Spring核心依赖 -->
<!-- spring-core-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- spring-beans-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- spring-context-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- Spring dao依赖 -->
<!-- spring-jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- spring-tx-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- Spring web依赖 -->
<!-- spring-web-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- spring-webmvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- Spring test依赖:方便做单元测试和集成测试 -->
<!-- spring-test-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
目标类
- 之前开发中,直接new一个对象即可
- 学习spring之后,将由spring创建对象实例->IOC 控制反转,之后需要实例化对象时,从spring工厂(容器)中获得,需要将实现类的全限定名称配置到xml文件中
public class HelloWord {
public void hello(){
System.out.println("Hello Spring");
}
}
配置文件
- 位置:任意
- 名称:任意,常用:appliactionContext.xml
- 内容:添加schema约束
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="helloWord" class="test.HelloWord"/>
</beans>
测试
public class TestIOC {
@Test
public void demo01() {
// 之前
HelloWord helloWord=new HelloWord();
helloWord.hello();
// 现在从spring容器获得
// 1:获得容器
// 2:获得内容--不需要自己new,都是从spring容器获得
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContent.xml");
HelloWord helloWord1= (HelloWord) ctx.getBean("helloWord");
helloWord1.hello();
}
结果
都可以输出Hello Spring
DI入门,依赖注入
is a :是一个,继承
has a:有一个,成员变量,依赖
class B{
private A a; //B类依赖A类
}
依赖:一个对象需要使用另一个对象
注入:通过setter方法进行另一个对象实例设置
class BookServiceImpl{
// 之前开发:接口=实现类(service和dao耦合)
pirvate BookDao bookDao=new BookDaoImpl();
//spring之后(解耦,service实现类使用dao的接口,不知道具体的实现类)
private BookDao bookDao();
setter();
}
模拟spring执行过程:
创建service实例:BookService bookService=new BookServiceImpl();–>IOC
创建dao实例:BookDao bookDao=new BookDaoImpl(); -->IOC
将dao设置给service:bookService.setBookDao(bookDao); -->DI
dao
public interface BookDao {
public void addBook();
}
public class BookDaoImpl implements BookDao {
@Override
public void addBook() {
System.out.println("添加书籍");
}
}
service
public interface BookService {
public void addBook();
}
public class BookServiceImpl implements BookService {
// 方式一:
// BookDao bookDao = new BookDaoImpl();
// 方式二:
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
@Override
public void addBook() {
this.bookDao.addBook();
}
}
配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!-- 创建service实例:BookService bookService=new BookServiceImpl();–>IOC-->
<!-- 将dao设置给service:bookService.setBookDao(bookDao); –>DI-->
<!-- 创建dao实例:BookDao bookDao=new BookDaoImpl(); –>IOC-->
<bean id="bookService" class="service.BookServiceImpl">
<!-- 属性注入-->
<!-- name:bean的属性名,通过setter方法获得-->
<!-- ref:另一个bean的id值的引用-->
<property name="bookDao" ref="bookDao"/>
</bean>
<bean id="bookDao" class="dao.BookDaoImpl"/>
</beans>
测试
public class test {
@Test
public void test() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContent.xml");
BookService bookService = (BookService) applicationContext.getBean("bookService");
bookService.addBook();
}
}
结果
核心API
- BeanFactory:工厂,生产任意bean(采用延迟加载,第一次getBean时才会初始化Bean)
- ApplicationContext:是BeanFactory的子接口,功能更强大(国际化,事件传递,Bean自动装配,各种不同应用层的Context实现),当配置文件被加载,就进行对象实例化。
- ClassPathXmlApplicationContext:用于加载xml
- FileSystemXmlApplicationContext:用于加载指定盘符下的xml
装配Bean基于XML
实例化方式
- 默认构造
<bean id="bookService" class="service.BookServiceImpl">//必须提供默认工厂
- 静态工厂
- 常用与spring整合其他框架(工具)
- 静态工厂:用于生成实例对象,所有的方法必须是__static__
<bean id="" class="工厂全限定类名" factory-method="静态工厂方法">
工厂
public class MyBeanFactory {
public static UserService createService() {
return new UserServiceImpl();
}
}
spring配置
<bean id="myBeanFactory" class="test.MyBeanFactory" factory-method="createService"/>
静态工厂测试
@Test
public void test02() {
//自定义静态工厂
UserService userService = MyBeanFactory.createService();
userService.addUser();
//spring工厂
// class 确定静态工厂全限定类名
// factory-method 确定静态方法名
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContent.xml");
UserService userService1 = (UserService) applicationContext.getBean("myBeanFactory",UserService.class);
userService1.addUser();
}
结果:控制台输出add user
- 实例工厂
- 必须先有工厂实例对象,通过实例对象创建对象。提供所有的方法都是__非静态__的
工厂类
- 必须先有工厂实例对象,通过实例对象创建对象。提供所有的方法都是__非静态__的
public class MyBeanFactory {
public UserService createService() {
return new UserServiceImpl();
}
}
spring配置
<!-- factory-bean:确定工厂实例-->
<!-- factory-method:确定普通方法-->
<bean id="myBeanFactory" class="test.MyBeanFactory"/>
<bean id="userService" factory-bean="myBeanFactory" factory-method="createService"/>
工厂测试
@Test
public void test03() {
//自定义实例工厂
MyBeanFactory myBeanFactory = new MyBeanFactory();
UserService userService = myBeanFactory.createService();
userService.addUser();
// spring实例工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContent.xml");
UserService userService1 = applicationContext.getBean("userService", UserService.class);
userService1.addUser();
}
Bean种类
- 普通bean:之前操作的都是普通bean。,spring直接创建A实例,并返回
- FactoryBean:是一个特殊的bean,具有工厂生成对象能力,只能生成特定的对象。
- bean必须实现FactoryBean接口,此接口提供方法getObject()用于获得特定bean。
- 先创建FB实例,使用调用getObject()方法,并返回方法的返回值
- FB fb=bew FB();return fb.getObject();
- BeanFactory和FactoryBean对比?
- BeanFactory:工厂,用于生成任意bean
- FactoryBean:特殊bean,用于生成另一个特定的bean:例如:ProxyFactoryBean,此工厂bean用于生产代理的。获得代理对象实例,AOP使用
作用域
用于确定spring创建实例的个数
- 取值
- singleton :单例,默认值
- prototype:每执行一次getBean将获得一个实例。例如:struts整合spring,配置action多例。
- 配置信息
<bean id="" class="" scope="">
测试
<bean id="userService" class="service.UserServiceImpl" scope="singleton"/>
<bean id="userService" class="service.UserServiceImpl" scope="prototype"/>
生命周期
- 初始化(准备数据)和销毁(清理资源)
目标方法执行前和执行后,将进行初始化或者销毁
<bean id="" class="" init-method="初始化方法名称" destory-method="销毁的方法名称">
初始化
<bean id="userService" class="service.UserServiceImpl" init-method="myInit"/>
销毁(容器必须close,销毁方法才能执行,并且必须是单例的)
<bean id="userService" class="service.UserServiceImpl"destroy-method="myDestroy"/>
applicationContext.close();
- BeanPostProcessor 后处理Bean
spring提供一种机制,只要实现此接口BeanPostProcessor,并将实现类提供给spring容器,spring容器将自动执行,在初始化方法前执行before(),在初始化方法后执行after()。
Spring提供的工厂钩子,用于修改实例对象,可以生成代理对象,是AOP底层。
模拟:
A a=new A();
a=B.before(); -->将a的实例对象传递后处理bean,可以生成代理对象并返回
a.init();
a=B.after();
a.addUser(); -->生成代理对象,目的在目标方法前后执行(例如:开启事务,提交事务)
a.destory();
后处理bean
public class myBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
// return null;//之后使用会出现空指针异常NullPointerException
return o;
}
@Override
public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
//生成代理
return Proxy.newProxyInstance(myBeanPostProcessor.class.getClassLoader(), o.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开启事务");
Object obj = method.invoke(o, args);
System.out.println("关闭事务");
return obj;
}
});
}
}
spring配置
<bean id="userService" class="service.UserServiceImpl"/>
<bean class="test.myBeanPostProcessor"/>
测试
System.out.println(userService1);
结果
- 问题1:后处理bean作用某一个目标类,还是所有目标类?
所有 - 如何只作用一个?
通过参数2,String s进行控制
属性依赖注入
- 依赖注入方式:手动装配和自动装配
- 手动装配:一般进行配置信息都采用手动
- 基于xml装配:构造方法,setter方法
- 基于注解装配:
- 自动装配:struts2和spring整合可以自动装配
- byType:按类型装配
- byName:按名称装配
- constructor:构造装配
- auto:不确定装配
构造方法
public class User {
private Integer uid;
private String username;
private Integer age;
public User(Integer uid, String username) {
this.uid = uid;
this.username = username;
}
public User(String username, Integer age) {
this.username = username;
this.age = age;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"uid=" + uid +
", username='" + username + '\'' +
", age=" + age +
'}';
}
}
@Test
public void test04() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContent.xml");
User user = applicationContext.getBean("user", User.class);
System.out.println(user);
}
<!-- 构造方法注入-->
<!-- constructor-arg用于配置构造方法的一个参数argument-->
<!-- name:参数的名称-->
<!-- value:数据类型-->
<!-- ref:另一个bean的id值-->
<!-- index:参数的索引号,从0开始。如果只有索引,比配到了多个构造方法时,默认使用第一个-->
<!-- type:确定参数类型-->
<!-- 例如:使用名称-->
<!-- <constructor-arg name="username" value="jack"/>-->
<!-- <constructor-arg name="age" value="18"/>-->
<!-- 例如:使用类型type和索引index-->
<!-- <constructor-arg index="0" type="java.lang.String" value="jack"/>-->
<!-- <constructor-arg index="1" type="java.lang.Integer" value="18"/>-->
<bean id="user" class="test.User">
<!-- <constructor-arg name="username" value="jack"/>-->
<!-- <constructor-arg name="age" value="18"/>-->
<constructor-arg index="0" type="java.lang.String" value="jack"/>
<constructor-arg index="1" type="java.lang.Integer" value="18"/>
</bean>
setter方法
public class Person {
private String name;
private Address homeAddress;
private Integer age;
private Address companyAddress;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getHomeAddress() {
return homeAddress;
}
public void setHomeAddress(Address homeAddress) {
this.homeAddress = homeAddress;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Address getCompanyAddress() {
return companyAddress;
}
public void setCompanyAddress(Address companyAddress) {
this.companyAddress = companyAddress;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", homeAddress=" + homeAddress +
", age=" + age +
", companyAddress=" + companyAddress +
'}';
}
}
public class Address {
private String description;
private String telephone;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getTelephone() {
return telephone;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
@Override
public String toString() {
return "Address{" +
"description='" + description + '\'' +
", telephone='" + telephone + '\'' +
'}';
}
}
<bean id="person" class="test.Person">
<property name="name" value="jack"/>
<property name="age" value="12"/>
<property name="companyAddress" ref="companyAddress"/>
<property name="homeAddress" ref="homeAddress"/>
</bean>
<bean id="companyAddress" class="test.Address">
<property name="description" value="张家港"/>
<property name="telephone" value="231"/>
</bean>
<bean id="homeAddress" class="test.Address">
<property name="description" value="苏州"/>
<property name="telephone" value="1433223"/>
</bean>
@Test
public void test04() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContent.xml");
Person person = applicationContext.getBean("person", Person.class);
System.out.println(person);
}
p命名空间【了解】
- 对setter方法注入进行简化,替换,而是在<bean p:属性名=“普通值” p:属性名-ref=“引用值”>
- p命名空间使用提前,必须添加命名空间
xmlns:p="http://www.springframework.org/schema/p"
<bean id="person" class="test.Person" p:name="jack" p:age="13" p:companyAddress-ref="companyAddress"
p:homeAddress-ref="homeAddress">
</bean>
<bean id="companyAddress" class="test.Address" p:description="北京" p:telephone="1433223">
</bean>
<bean id="homeAddress" class="test.Address" p:description="四川" p:telephone="321">
</bean>
SpEL【了解】
- 对进行统一编程,所有的内容都使用value
<bean id="person" class="test.Person">
<property name="age" value="#{'12'}"/>
<property name="name" value="#{person.name?.toUpperCase()}"/>
<property name="homeAddress" value="#{homeAddress}"/>
<property name="companyAddress" value="#{companyAddress}"/>
</bean>
<bean id="companyAddress" class="test.Address">
<property name="telephone" value="#{'213'}"/>
<property name="description" value="#{'黑龙江'}"/>
</bean>
<bean id="homeAddress" class="test.Address">
</bean>
结果
集合注入
public class CollData {
private String[] arrayData;
private List<String> listData;
private Set<String> setData;
private Map<String, String> mapData;
private Properties properties;
public String[] getArrayData() {
return arrayData;
}
public void setArrayData(String[] arrayData) {
this.arrayData = arrayData;
}
public List<String> getListData() {
return listData;
}
public void setListData(List<String> listData) {
this.listData = listData;
}
public Set<String> getSetData() {
return setData;
}
public void setSetData(Set<String> setData) {
this.setData = setData;
}
public Map<String, String> getMapData() {
return mapData;
}
public void setMapData(Map<String, String> mapData) {
this.mapData = mapData;
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "CollData{\n" +
"arrayData=" + Arrays.toString(arrayData) +
",\n listData=" + listData +
",\n setData=" + setData +
",\n mapData=" + mapData +
",\n properties=" + properties +
"}\n";
}
}
<bean id="collData" class="test.CollData">
<property name="arrayData">
<array>
<value>array01</value>
<value>array02</value>
<value>array03</value>
</array>
</property>
<property name="listData">
<list>
<value>list01</value>
<value>list02</value>
<value>list03</value>
</list>
</property>
<property name="setData">
<set>
<value>set01</value>
<value>set02</value>
<value>set03</value>
</set>
</property>
<property name="mapData">
<map>
<entry key="one" value="map01"/>
<entry key="two" value="map02"/>
<entry key="three" value="map03"/>
</map>
</property>
<property name="properties">
<props>
<prop key="1">prop01</prop>
<prop key="2">prop02</prop>
<prop key="3">prop03</prop>
</props>
</property>
</bean>
结果
装配Bean基于注解
- 注解:就是一个类,使用@注解名称
- 开发中:使用注解取代xml配置
@Component(’'id")取代<bean id="",class="">
注解使用前提,添加命名空间,让spring扫描含有注解的类
<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="service"/>
@Test
public void test04() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContent.xml");
UserService userService = applicationContext.getBean("userService", UserServiceImpl.class);
userService.addUser();
}
结果:add user
- web开发,提供3个@Component注解衍生注解(功能一样)
- @Repository:dao层
- @Service:service层
- @Controller:web层
- 依赖注入,给私有字段设置,也可以给setter方法设置
- 普通值:@Value(“”);
- 引用值
- 按照【类型注入】@Autowired
- 按照【名称注入】@Autowired @Qualifier(“名称”)或者@Resource(“名称”)
@Controller("studentAction")
public class StudentAction extends ActionSupport {
@Autowired
private StudentService studentService;
@Override
public String execute() throws Exception {
studentService.add();
return NONE;
}
}
@Service
public class StudentServiceImp implements StudentService {
private StudentDao studentDao;
@Autowired
@Qualifier("studentDao")
public void setStudentDao(StudentDao studentDao) {
this.studentDao = studentDao;
}
@Repository("studentDao")
public class StudentDaoImpl implements StudentDao{
@Override
public void add() {
System.out.println("add student");
}
}
@Test
public void test04() throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContent.xml");
StudentAction studentAction = applicationContext.getBean("studentAction", StudentAction.class);
String res=studentAction.execute();
}
结果:add student
- 声明周期
- 初始化:@PostConstruct
- 销毁:@PreDestory
- 作用域
- 默认:单例
- 多例:@Scope(“prototype”)
AOP(切面编程),JdbcTemplate
AOP
Aop介绍
什么是AOP
- 面向切面编程,通过与便于方式和运行期间动态代理实现程序功能的统一维护的一种技术。降低耦合度,提高代码的可重用性。
- AOP采用__横向抽取__机制,取代了传统__纵向继承__体系重复性代码
- 经典应用:事务管理、性能监控、安全检查、缓存
- Spring AOP使用纯java实现,不需要专门的编译过程和类加载器,在运行期间通过代理方式向目标类织入增强代码
- AspectJ是一个基于java语言的AOP框架
AOP实现原理
- aop底层将采用代理机制进行实现
- 接口+实现类:spring采用jdk的__动态代理__Proxy
- 实现类:spring采用cglib字节码增强
AOP术语
- target:目标类,需要被代理的类
- Joinpoint(连接点):可能被拦截到的方法。
- PointCut(切入点):已经被增强的连接点
- advice(通知/增强):增强代码
- Weaving(织入):是把增强advice应用到目标对象target来创建新的搭理对象proxy的过程
- proxy:代理
- Aspect(切面):是切入点pointcut和通知advice的结合
####手动方式 - JDK动态代理
- JDK动态代理对"装饰者"设计模式简化。使用前提:必须有接口
1.目标类:接口+实现类
- JDK动态代理对"装饰者"设计模式简化。使用前提:必须有接口
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("add user");
}
@Override
public void updateUser() {
System.out.println("update user");
}
@Override
public void deleteUser() {
System.out.println("delete user");
}
}
2.切面类:用于存通知MyAspect
public class MyAspect {
public void before(){
System.out.println("before");
}
public void after(){
System.out.println("after");
}
}
3.工厂类:编写工厂生成代理
public class MyBeanFactory {
public static UserService createService() {
UserService userService = new UserServiceImpl();
MyAspect myAspect = new MyAspect();
UserService proxyUserService = (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 proxyUserService;
}
}
4.测试
@Test
public void test05() {
UserService userService=MyBeanFactory.createService();
userService.addUser();
userService.deleteUser();
userService.updateUser();
}
结果
before
add user
after
before
delete user
after
before
update user
after
- CGLIB字节码增强(目标类没有接口)
- 没有接口,只有实现类
- 采用字节码增强框架cglib,在运行时创建目标类的子类,从而对目标类进行增强。
- spring-core已经引入jar包
public class MyBeanFactory {
public static UserServiceImpl createService() {
UserServiceImpl userService = new UserServiceImpl();
MyAspect myAspect = new MyAspect();
// 核心类
Enhancer enhancer = new Enhancer();
// 确定父类
enhancer.setSuperclass(userService.getClass());
// 设置回调函数
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
myAspect.before();
// 执行目标类的方法
Object object = method.invoke(userService,objects);
// 执行代理类的父类,就是目标类
methodProxy.invokeSuper(o,objects);
myAspect.after();
return object;
}
});
UserServiceImpl proxyUserService = (UserServiceImpl) enhancer.create();
return proxyUserService;
}
}
AOP联盟通知类型
前置通知,后置通知,环绕通知,异常抛出通知
环绕通知必须手动执行目标方法
try{
//前置通知
//执行目标方法
//后置通知
}catch(){
//抛出异常通知
}
spring编写代理:半自动
- 让spring创建代理对象,从spring容器中手动的获取代理对象
- jar包:核心4+1(core,beans,context,expression,aop),commons-logging(日志),aop联盟(aopalliance)
- 低层机制:
- 如果目标类有接口,采用jdk动态代理
- 如果没有接口,采用cglib字节码增强
<bean id="userService" class="test.UserServiceImpl">
</bean>
<!-- 切面类-->
<bean id="myAspect" class="test.MyAspect">
</bean>
<!-- //创建代理工厂bean,生成特殊代理对象-->
<bean id="proxyUserService" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 确定接口们-->
<property name="interfaces" value="test.UserService"/>
<!-- 确定目标类-->
<property name="target" ref="userService"/>
<!-- 通知切面类的名称-->
<property name="interceptorNames" value="myAspect"/>
<!-- 强制使用cglib-->
<!-- <property name="optimize" value="true"/>-->
</bean>
public class MyAspect implements MethodInterceptor {
// public void before() {
// System.out.println("before");
// }
//
// public void after() {
// System.out.println("after");
// }
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("before");
Object object=methodInvocation.proceed();
System.out.println("after");
return object;
}
}
spring aop编程:全自动【掌握】
- 从spring容器获得目标类,如果配置aop,spring将自动生成代理
- 要确定目标类,要使用aspectj切入点表达式
导入命名空间
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
<!-- 目标类-->
<bean id="userService" class="test.UserServiceImpl"/>
<!-- 切面类(通知)-->
<bean id="myAspect" class="test.MyAspect"/>
<!-- aop编程-->
<!-- 1.导入命名空间-->
<!-- 2.使用<aop:config>-->
<!-- <aop:pointcut>切入点,从目标对象获得具体方法-->
<!-- <aop:advisor>特殊的切面,只有一个通知和一个切入点-->
<!-- advice-ref通知引用-->
<!-- pointcut-ref切入点引用-->
<!-- 3.切入点表达式-->
<!-- execution(* test.UserServiceImpl.*.*(..))-->
<!-- 4.proxy-target-class="true"是否使用cglib代理-->
<aop:config proxy-target-class="true">
<aop:pointcut expression="execution(* test.UserServiceImpl.*(..))" id="myPointCut"/>
<aop:advisor advice-ref="myAspect" pointcut-ref="myPointCut"/>
</aop:config>
public class MyAspect implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("before");
Object object=methodInvocation.proceed();
System.out.println("after");
return object;
}
}
AspectJ
介绍
- 基于java语言的AOP框架
- spring2.0以后新增了对AspectJ切点表达式的支持
切入点表达式【掌握】
- execution()用于描述方法
- 语法:execution(修饰符 返回值 包.类.方法(参数)throws 异常)
|修饰符,一般省略|返回值|包【省略】|类【省略】|方法,不可省略|参数|throws,【省略】|
|—|:-😐:–|—|---|—|–|
|public,公共方法|void,返回没有值|com.crm,固定包|UserServiceImpl,指定类|addUser,固定方法|(),无参|标明异常|
|,任意|String,返回值字符串|com.crm..service,crm包下面子包任意(com.crm.staff.service)|Impl,以Impl结尾|add,以add开头|(int),一个整型||
||,任意|com.crm…,crm包下的所有子包(含自己)|User,以User开头|Do,以Do结尾|(int,int)两个整型||
|||com.crm..service…,crm包下面任意子包,固定目录service,service目录任意包|,任意|,任意|(…)参数任意||
综合1:execution(* com.crm.* .service….(…)))
综合2:execution(省略1)||execution(省略2),都能匹配
- 语法:execution(修饰符 返回值 包.类.方法(参数)throws 异常)
- 其他语法(了解,用到时在了解也行)
- within:匹配包或子包中的方法
- this:匹配实现接口的代理对象中的方法
- target:匹配实现接口的目标对象中的方法
- args:匹配参数格符合标准的方法
- bean(id):对指定的bean中的所有方法
AspectJ通知类型
- aop联盟定义通知类型具有特点接口,必须实现,从而确定方法的名称。
- aspectj通知类型,只定义了类型的名称,以及方法的格式。
- 通知类型(六种,了解5种):
- before:方法前执行,如果通知抛出异常,阻止方法运行
- afterReturning:方法后执行,如果方法抛出异常,通知无法执行
- around:可以做任何事,但是必须手动执行目标方法
- afterThrowing:抛出异常后执行,没抛出异常则不执行
- after:无论是否出现异常,都会执行
环绕
try{
//前置:before
手动执行目标方法
//后置:afterReturning
}catch(){
//抛出异常:afterThrowing
}finally{
//最终:after
}
基于xml
1:目标类:接口+实现
2:切面类:编写多个通知,采用aspectj,通知名称任意(方法名任意)
3:aop编程:将通知应用到目标类
4:测试
实现类
public class UserServiceImpl implements UserService {
public void addUser() {
System.out.println("add user");
}
public String updateUser() {
System.out.println("update user");
return "更新用户完成";
}
@Override
public void queryUser() {
System.out.println("查找用户");
}
public void deleteUser() {
System.out.println("delete user");
}
}
spring配置
<bean class="test.UserServiceImpl" id="userService"/>
<bean class="test.MyAspect" id="myAspect"/>
<aop:config>
<!-- 将切面类声明成"切面",从而去获得通知-->
<aop:aspect ref="myAspect">
<!--切入点表达式-->
<!-- expression:切入点表达式,标明了对那些切入点做增强功能-->
<!-- id:切入点的名称,自己随便取-->
<aop:pointcut expression="execution(* test.UserServiceImpl.*(..))" id="myPointCut"/>
<!-- 前置通知-->
<!-- method:哪个是前置通知-->
<!-- pointcut-ref:切入点引用,和别的通知共享切入点-->
<!-- 或者使用pointcut:此表达式只能当前通知使用-->
<aop:before method="MethodBeforeAdvice" pointcut="execution(* test.UserServiceImpl.deleteUser(..))"/>
<!-- 后置通知,方法后执行,可能有返回值-->
<!-- returning:把连接点方法的返回值给ret,那么增强方法就能获得这个参数,MethodAfterAdvice(Object ret)-->
<aop:after-returning method="MethodAfterAdvice" pointcut-ref="myPointCut" returning="ret"/>
<!-- 环绕通知-->
<!-- 格式:public Object SurroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable-->
<!-- 返回值类型:Object-->
<!-- 传参类型:ProceedingJoinPoint-->
<!-- 抛出异常:throws Throwable-->
<!-- 手动执行目标方法:Object object = joinPoint.proceed()-->
<aop:around method="SurroundAdvice" pointcut="execution(* test.UserServiceImpl.updateUser(..))"/>
<!-- 抛出异常通知-->
<!-- 通知方法格式: public void exceptionAdvice(JoinPoint joinPoint,Throwable e)-->
<!-- throwing:把抛出的异常信息配置到通知中-->
<aop:after-throwing method="exceptionAdvice" pointcut="execution(* test.UserServiceImpl.queryUser(..))"
throwing="e"/>
<!-- 最终通知,相当于try-catch中的finally,肯定会执行-->
<aop:after method="finallyAdvice" pointcut-ref="myPointCut"/>
</aop:aspect>
</aop:config>
@Test
public void test07() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContent.xml");
UserService userService = (UserService) applicationContext.getBean("userService");
userService.addUser();
userService.deleteUser();
userService.queryUser();
userService.updateUser();
}
测试结果
基于注解
spring配置,扫描注解,扫描aspectJ
<aop:aspectj-autoproxy proxy-target-class="true"/>
<context:component-scan base-package="test"/>
- 替换bean
@Service("userService")
public class UserServiceImpl implements UserService {
@Component("myAspect")
public class MyAspect {
- 替换aop
@Component("myAspect")
@Aspect
public class MyAspect {
@Pointcut("execution(* test.UserService.*(..))")
// 方法名就是id
public void myPointCut() {
}
@Before("execution(* test.UserServiceImpl.addUser(..))")
//JoinPoint用于描述连接点
public void MethodBeforeAdvice(JoinPoint joinPoint) {
//getSignature:获取目标方法名
System.out.println("前置通知" + joinPoint.getSignature());
}
//value:相当于引用
@AfterReturning(value = "myPointCut()", returning = "ret")
public void MethodAfterAdvice(Object ret) {
System.out.println("后置通知" + "返回值:" + ret);
}
@Around("execution(* test.UserServiceImpl.deleteUser(..))")
public Object SurroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前");
Object object = joinPoint.proceed();
System.out.println("环绕后");
return object;
}
@AfterThrowing(value = "execution(* test.UserServiceImpl.queryUser(..))", throwing = "e")
public void exceptionAdvice(JoinPoint joinPoint, Throwable e) {
System.out.println("抛出异常" + e.toString());
}
@After(value = "execution(* test.UserServiceImpl.queryUser(..))")
public void finallyAdvice() {
System.out.println("finally");
}
}
注解总结
@Aspect | 声明切面。修饰切面类,从而获得通知 |
---|---|
@Before | 前置通知 |
@AfterReturning | 后置通知 |
@Around | 环绕通知 |
@AfterThrowing | 抛出异常通知 |
@After | 最终通知 |
@PointCut | 修饰方法,获得切入点引用 |
JdbcTemplate
- spring提供用于操作JDBC工具类(org.springframework.jdbc.core.JdbcTemplate),类似DBUtils
- 依赖连接池DataSource(数据源)
配置c3p0数据库连接池
<bean id="comboPooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf8"/>
<property name="user" value="root"/>
<property name="password" value="761020zy"/>
<property name="acquireIncrement" value="5"/>
<property name="initialPoolSize" value="10"/>
<property name="minPoolSize" value="5"/>
<property name="maxPoolSize" value="20"/>
</bean>
<bean class="dao.userDao" id="userDao">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
<property name="dataSource" ref="comboPooledDataSource"/>
</bean>
<bean class="domain.t_user" id="t_user">
<property name="id" value="1"/>
<property name="password" value="321"/>
<property name="username" value="李四"/>
</bean>
@Test
public void test08() throws SQLException {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContent.xml");
t_user user = (t_user) applicationContext.getBean("t_user");
userDao Dao = (userDao) applicationContext.getBean("userDao");
Dao.update(user);
}
}
public class userDao{
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void update(t_user user) {
String sql = "update t_user set username=?,password=? where id=?";
Object[] args = {user.getUsername(), user.getPassword(), user.getId()};
jdbcTemplate.update(sql, args);
}
}
如果要是用properties文件配置
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/test?characterEncoding=utf8
jdbc.user=root
jdbc.password=761020zy
spring配置文件要修改
<!-- 加载配置文件-->
<!-- classpath:表示src下-->
<context:property-placeholder location="classpath:jdbcinfo.properties"/>
<!-- 数据源-->
<bean id="comboPooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
事务管理
- 事务:一组业务操作,要么全部成功,要么全部失败
- 特性:ACID
- 原子性:整体
- 一致性:完成
- 隔离性:并发
- 持久性:结果
- 隔离问题
- 脏读:一个事务读到另一个事务没有提交的数据
- 不可重复读:一个事务读到另一个事务已提交的数据(update)
- 幻读(虚读):一个事务读到另一个事务已提交的数据(insert)
- 隔离级别
- read uncommitted:读未提交
- read committed:读已提交
- repeatable read:可重复读
- serializable:串行化(单事务)
- 假设有ABCD四个事件,事务如下
*执行过程:
*获得连接
*开启事务- A,B,C,D
成功:提交事务
出错:回滚事务
- A,B,C,D
- mysql事务操作-SavePoint需求:AB(必须),CD(可选)
- 保存点,记录操作的当前位置,之后可以回滚到指定的位置(可以回滚一部分)
- 获得连接
- 开启事务
- A
- B
- savepoint=conn.setSavepoint()
- C
- D
- 提交事务
- 如果报错,用catch捕获异常,分为下面两个情况
- 如果savepoint==null那么A,B异常,回滚到最开始
- 如果savepoint!=nul那么C,D异常,回滚到savepoint处
事务管理介绍
-
jar包:spring-tx
-
事务管理的三个顶级接口
|接口名|描述|
|:–|--|
|PlatformTransationManager|平台事务管理器,spring要管理事务,必须使用事务管理器|
|TransactionDefinition|事务详情(事务定义,事务属性),spring用于确定事务具体详情,例如:隔离级别,是否只读,超时时间等(进行事务配置时,必须配置详情。spring将配置项封装到该对象实例)|
|TransactionStatus|事务状态,spring用于记录当前事务运行状态。例如,是否有保存点,事务是否完成| -
常见的事务管理器:
- DataSourceTransactionManager:jdbc开发时事务管理器,采用JdbcTemplate
- TransactionStatus getTransaction(TransactionDefinition var1):事务管理器通过"事务详情"获得"事务状态"从而管理事务
- void commit(TransactionStatus var1):根据状态提交
- void rollback(TransactionStatus var1):根据状态回滚
- HibernateTransactionManager:hibernate开发时事务管理器,整合hibernate
- DataSourceTransactionManager:jdbc开发时事务管理器,采用JdbcTemplate
-
事务状态
- TransactionStatus
- boolean isNewTransaction():是否是新事务
- boolean hasSavepoint():是否有保存点
- void setRollbackOnly():设置回滚
- boolean is RollbackOnley():是否回滚
- void flush():是否属性
- boolean isCompleted():是否完成
- TransactionStatus
-
事务详情
- TransactionDefinition
- int getPropagationBehavior():传播行为
- int getIsolationLevel():隔离级别
- int getTimeout():获得超时时间
- boolean isReadOnly():是否只读(增删改:读写,查询:只读)
- String getName():配置事务详情名称
- ISOLATION_DEFAULT,ISOLATION_READ_UNCOMMITTED,ISOLATION_READ_COMMITTED,ISOLATION_REPEATABLE_READ,ISOLATION_SERIALIZABLE:隔离级别取值:0,1,2,4,8
- TIMEOUT_DEFAULT:默认超时时间
- TransactionDefinition
-
传播行为:在两个业务之间如何共享事务。
| int PROPAGATION_REQUIRED = 0 | 支持当前事务,A如果事务,B将使用该事务。如果A没有事务,B将创建一个新事务。 |
| :-------------------------------- | ------------------------------------------------------------ |
| int PROPAGATION_SUPPORTS = 1 | 支持当前事务,A如果事务,B将使用该事务。如果A没有事务,B将以非事务执行。 |
| int PROPAGATION_MANDATORY = 2 | 支持当前事务,A如果有事务,B将使用该事务。如果A没有事务,B将抛异常 |
| int PROPAGATION_REQUIRES_NEW = 3 | 如果A有事务,将A的事务挂起,B创建一个新的事务。如果A没有事务,B创建一个新的事务 |
| int PROPAGATION_NOT_SUPPORTED = 4 | 如果A有事务,将A的事务挂起,B将以非事务执行。如果A没有事务,B将以非事务执行 |
| int PROPAGATION_NEVER = 5 | 如果A有事务,B将抛异常。如果A没有事务,B将以非事务执行 |
| int PROPAGATION_NESTED = 6 | A和B底层采用保存点机制,形成嵌套事务。 |
案例:转账
搭建环境
数据库
create table if not exists account (
id int primary key auto_increment,
username varchar(50),
money int
);
insert into account(username,money)values('tom','5400');
insert into account(username,money)values('mike','1300');
insert into account(username,money)values('jack','10000');
insert into account(username,money)values('rose','10000');
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);
}
}
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);
accountDao.in(inner, money);
}
}
<context:property-placeholder location="jdbcinfo.properties"/>
<bean class="service.AccountServiceImpl" id="accountService">
<property name="accountDao" ref="accountDao"/>
</bean>
<bean class="dao.AccountDaoImpl" id="accountDao">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
<property name="dataSource" ref="comboPooledDataSource"/>
</bean>
<bean class="com.mchange.v2.c3p0.ComboPooledDataSource" id="comboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
<property name="acquireIncrement" value="${jdbc.acquireIncrement}"/>
<property name="initialPoolSize" value="${jdbc.initialPoolSize}"/>
<property name="minPoolSize" value="${jdbc.minPoolSize}"/>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"/>
</bean>
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/test?characterEncoding=utf8
jdbc.user=root
jdbc.password=761020zy
jdbc.acquireIncrement=5
jdbc.initialPoolSize=10
jdbc.minPoolSize=5
jdbc.maxPoolSize=20
maven依赖
- 核心:4+1
- aop:4(aop联盟,spring aop,aspectj规范,spring aspect)
- 数据库:2(jdbc,tx)
- 连接池:c3p0
手动管理事务
- spring底层使用TransactionTemplate事务模板进行操作
- 操作
- sevice需要获得TransactionTemplate
- spring配置模板,并注入给service
- 模板需要注入事务管理器
- 配置事务管理器:DataSourceTransactionManager
添加的内容
private TransactionTemplate transactionTemplate;
@Override
public void transfer(String outer, String inner, Integer money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
accountDao.out(outer, money);
accountDao.in(inner, money);
}
});
}
<bean class="service.AccountServiceImpl" id="accountService">
<property name="accountDao" ref="accountDao"/>
<property name="transactionTemplate" ref="transactionTemplate"/>
</bean>
<bean class="org.springframework.transaction.support.TransactionTemplate" id="transactionTemplate">
<property name="transactionManager" ref="dataSourceTransactionManager"/>
</bean>
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" name="dataSourceTransactionManager">
<property name="dataSource" ref="comboPooledDataSource"/>
</bean>
工厂bean生成代理:半自动
- spring提供 管理事务的代理工厂bean:TransactionProxyFactoryBean
- getBean()获得代理对象
- spring配置一个代理
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);
accountDao.in(inner, money);
}
<context:property-placeholder location="jdbcinfo.properties"/>
<bean class="service.AccountServiceImpl" id="accountService">
<property name="accountDao" ref="accountDao"/>
<!-- <property name="transactionTemplate" ref="transactionTemplate"/>-->
</bean>
<!-- 此处的org.springframework.transaction.support.TransactionTemplate的控制翻转可以删除-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" name="dataSourceTransactionManager">
<property name="dataSource" ref="comboPooledDataSource"/>
</bean>
<bean class="dao.AccountDaoImpl" id="accountDao">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
<property name="dataSource" ref="comboPooledDataSource"/>
</bean>
<bean class="com.mchange.v2.c3p0.ComboPooledDataSource" id="comboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
<property name="acquireIncrement" value="${jdbc.acquireIncrement}"/>
<property name="initialPoolSize" value="${jdbc.initialPoolSize}"/>
<property name="minPoolSize" value="${jdbc.minPoolSize}"/>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"/>
</bean>
<bean class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
id="transactionProxyFactoryBean">
<!-- 事务管理器-->
<property name="transactionManager" ref="dataSourceTransactionManager"/>
<!-- 目标类-->
<property name="target" ref="accountService"/>
<!-- 接口-->
<property name="proxyInterfaces" value="service.AccountService"/>
<!-- 事务属性(事务详情)-->
<property name="transactionAttributes">
<props>
<!-- key:那些方法使用当前事务配置-->
<!-- text:配置事务详情-->
<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop>
</props>
</property>
</bean>
AOP配置基于xml
- 在spring xml配置aop自动生成代理,进行事务的管理
- 配置管理器
- 配置事务详情
- 配置aop
<context:property-placeholder location="jdbcinfo.properties"/>
<bean class="service.AccountServiceImpl" id="accountService">
<property name="accountDao" ref="accountDao"/>
</bean>
<bean class="dao.AccountDaoImpl" id="accountDao">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
<property name="dataSource" ref="comboPooledDataSource"/>
</bean>
<bean class="com.mchange.v2.c3p0.ComboPooledDataSource" id="comboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
<property name="acquireIncrement" value="${jdbc.acquireIncrement}"/>
<property name="initialPoolSize" value="${jdbc.initialPoolSize}"/>
<property name="minPoolSize" value="${jdbc.minPoolSize}"/>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"/>
</bean>
<!-- 事务管理-->
<!-- 事务管理器-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="dataSourceTransactionManager">
<property name="dataSource" ref="comboPooledDataSource"/>
</bean>
<!--在aop的筛选基础上,对abc三个确定使用什么样的事务-->
<tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager">
<!-- 事务详情-->
<tx:attributes>
<tx:method name="transfer" propagation="REQUIRED" isolation="DEFAULT"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="point" expression="execution(* service..*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="point"/>
</aop:config>
AOP配置基于注解
- 配置事务管理器,并将事务管理器交给spring
- 在目标类或目标方法添加注解即可@Transactional
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="dataSourceTransactionManager">
<property name="dataSource" ref="comboPooledDataSource"/>
</bean>
<!-- proxy-target-class="true"使用cglib获得对象-->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager" proxy-target-class="true"/>
</beans>
@Transactional
public class AccountServiceImpl implements AccountService {
//或者加在方法前面,如果写在类前面表示对所有方法都开启事务
@Transactional
@Override
public void transfer(String outer, String inner, Integer money) {
事务详情配置
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT)
整合Junit
jar包:spring-text
原来 | 整合之后 |
---|---|
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(“applicationContext.xml”); | @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations=“classpath:applicationContext.xml”) |
AccountService accountService = applicationContext.getBean(“accountService”, AccountService.class); | @Autowired private AccountService accountService; |
整合WEB
- jar包:spring-web
*tomcat启动加载配置文件- servlet->init(ServletConfig)->2
- filter->init(FilterConfig)->web.xml注册过滤器自动调用初始化
- listener->ServletContextListener->servletContext对象监听
- spring提供监听器ContextLoaderListener->web,xml
<listener>
<!-- 默认加载/WEB-INF/applicationContext.xml-->
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
- 确定配置文件位置,通过系统初始化参数
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<display-name>Archetype Created Web Application</display-name>
- 从servletContext作用域获得spring容器【了解】
// 从application作用域(ServletContext)获得spring容器
// 方式一:手动从作用域获取
// ApplicationContext applicationContext= (ApplicationContext) this.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
// 方式二:用工具获取
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
accountService.transfer("jack", "rose", 100);
SSH整合
struts:2.3.15.3
hibernate:3.6.10
spring:3.2.0
###jar包整合
数据库
驱动:mysql
连接池:c3p0
hibernate
hibernate-core
slf4j:日志
jta:javatransaction规范
javassist:字节码增强
dom4j:java集合
common-collections:java集合增强
antlr:表达式解析
hibernate-jpa:jpa规范,hibernate注解开发
spring
基础:bean,core,context,expression,common-logging
AOP:aop联盟,spring aop,aspect规范,spring aspect
db:jdbc,tx
测试:test
web开发:spring web
整合hibernate:spring orm
struts
asm,asm-commons,asm-tree:字节码增强框架
xwork-core:webwork核心
struts2-core:进一步封装
ognl:OGNL表达式,值栈的底层实现
log4j:日志
javassist:字节码增强
freemarker:模板技术
commons-logging,lang,io,fileupload:日志,lang包增强,io增强,文件上传struts2-spring-plugin:整合spring
/WEB-INF/applicationContext.xml–>
org.springframework.web.context.ContextLoaderListener
* 确定配置文件位置,通过系统初始化参数
```xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<display-name>Archetype Created Web Application</display-name>
- 从servletContext作用域获得spring容器【了解】
// 从application作用域(ServletContext)获得spring容器
// 方式一:手动从作用域获取
// ApplicationContext applicationContext= (ApplicationContext) this.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
// 方式二:用工具获取
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
accountService.transfer("jack", "rose", 100);
SSH整合
struts:2.3.15.3
hibernate:3.6.10
spring:3.2.0
###jar包整合
数据库
驱动:mysql
连接池:c3p0
hibernate
hibernate-core
slf4j:日志
jta:javatransaction规范
javassist:字节码增强
dom4j:java集合
common-collections:java集合增强
antlr:表达式解析
hibernate-jpa:jpa规范,hibernate注解开发
spring
基础:bean,core,context,expression,common-logging
AOP:aop联盟,spring aop,aspect规范,spring aspect
db:jdbc,tx
测试:test
web开发:spring web
整合hibernate:spring orm
struts
asm,asm-commons,asm-tree:字节码增强框架
xwork-core:webwork核心
struts2-core:进一步封装
ognl:OGNL表达式,值栈的底层实现
log4j:日志
javassist:字节码增强
freemarker:模板技术
commons-logging,lang,io,fileupload:日志,lang包增强,io增强,文件上传struts2-spring-plugin:整合spring