一、Spring的概述
Spring是一个分层的Java EE/SE开发的一站式框架。
一站式:有每一层的解决方案。
WEB层:SpringMVC
Service层:Spring的Bean管理,Spring声明式事务
DAO层:Spring的JDBC模板,Spring的ORM模板
二、Spring运行架构
三、Spring IOC
IOC:Inversion of Control(控制反转),将对象的创建权反转给(交给)Spring。
1.IOC的底层实现
2.示例
(1)下载spring
http://spring.io/
(2)相关文件夹说明
(3)创建项目导入jar包
(4)编写接口和实现类
①.User接口
public interface User {
public void test();
}
②.UserImpl和CustomerImpl
public class UserImpl implements User {
public void test() {
// TODO Auto-generated method stub
System.out.println("UserImpl");
}
}
public class CustomerImpl implements User {
public void test() {
// TODO Auto-generated method stub
System.out.println("CustomerImpl");
}
}
③.配置文件
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Spring配置 -->
<bean name="user" class="pers.zx.spring.test.UserImpl" />
④.测试类
public class TestSpring {
@Test
public void test() {
ApplicationContext a=new ClassPathXmlApplicationContext("applicationContext.xml");
User user=(User)a.getBean("user");
user.test();
}
}
此时调用不同的类只需要修改配置文件就可以了。
四、IOC与DI
IOC:控制反转,将对象的创建权反转给了spring。
DI:依赖注入,前提是必须有IOC的环境,Spring管理这个类的时候将类的依赖的属性注入(设置)进来。
<bean name="user" class="pers.zx.spring.test.UserImpl" >
<property name="name" value="zx" />
</bean>
把name属性依赖(设置)到UserImpl类中。
五、Spring工厂类
1.工厂类结构图
2.FactoryBean与ApplicationContext区别
以上是两个工厂类,FactoryBean是老版的工厂类,ApplicationContext是新版的工厂类。
区别:
1.BeanFactory:调用getBean的时候,才会生成类的实例。
2.ApplicationContext:加载配置文件的时候,就会将Spring管理的类都实例化。
3.ApplicationContext的两个实现类
ClassPathXmlApplicationContext :加载类路径下的配置文件
FileSystemXmlApplicationContext :加载文件系统下的配置文件
六、Spring配置
1.Schema配置
复制.xsd的连接,window–>preference–>XML–>XML CataLog,按照下图配置
2.Bean的相关配置
(1)< bean>标签的id和name
id:使用了约束中的唯一约束。里面不能出现特殊字符的。
name:没有使用约束中的唯一约束(理论上可以出现重复的,但是实际开发不能出现的)。里面可以出现特殊字符。
即在使用getBean时,可以通过name调用也可以通过id调用。
在老的项目中会这样配置:有个斜杠
<bean name="/user" class="" />
(2)< bean>的生命周期的配置
init-method:Bean被初始化的时候执行的方法
destroy-method:Bean被销毁的时候执行的方法(Bean是单例创建,工厂关闭)
<bean id="user" class="" init-method="" destroy-method=""/>
(3)< bean>的作用范围的配置
scope:
1.singleton:默认的,Spring会采用单例模式创建这个对象。
2.prototype:多例模式。
3.request:应用在web项目中,Spring创建这个类以后,将这个类存入到request范围中。
4.session:应用在web项目中,Spring创建这个类以后,将这个类存入到session范围中。
5.globalsession:应用在web项目中,必须在porlet环境下使用。但是如果没有这种环境,相对于session。
注意:
1.单例模式:每次用只创建一个对象,每次new的是同一个对象
2.多例模式:每次用都创建不同的对象,每次new的都是新的对象
3.Porlet环境:有子应用的程序,只要在父应用登陆过,子应用就不用登陆就可以实现操作。
七、Spring属性注入
1.设置属性的方式
2.Spring的构造方法注入
<bean name="user" class="pers.zx.spring.test.UserImpl">
<constructor-arg name="name" value="zx" />
<constructor-arg name="age" value="20" />
</bean>
private String name;
private Integer age;
public UserImpl(String name,Integer age){
this.age=age;
this.name=name;
}
3.Spring的set方法注入
private String name;
privete Integer age;
private Customer customer;
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
<bean name="user" class="pers.zx.spring.test.UserImpl">
<property name="name" value="zx" />
<property name="age" value="10" />
</bean>
<bean name="user" class="pers.zx.spring.test.UserImpl">
<property name="name" value="zx" />
<!-- value:设置普通类型的值 ref:设置其他的类的id或name -->
<property name="customer" ref="customer" />
</bean>
4.P名称空间的属性注入
(1)引入名称空间
(2)编写xml
普通属性 p:属性名=”值”
对象属性 p:属性名-ref=”值”
(3)例子
<bean name="user" class="pers.zx.spring.test.UserImpl" p:name="zx" p:age="10" />
<bean name="user" class="pers.zx.spring.test.UserImpl" p:name="zx" p:Customer-ref="customer"/>
5.SpEL属性注入
SpEL:Spring Expression Language,Spring的表达式语言。
其他不变,只是把bean中的value=””换成SpEL。
语法:#{ }
字符串:#{'字符串'}
数值:#{20.0}
对象:#{obj}
对象属性:#{obj.value}
对象方法:#{obj.method()}
<bean name="user" class="pers.zx.spring.test.UserImpl">
<property name="name" value="#{'zx'}" />
<property name="age" value="#{20.0}" />
</bean>
or
<!--先引入其他对象再调用其方法-->
<bean name="obj" class="pers.zx.spring.test.ObjMessage"/>
<bean name="user" class="pers.zx.spring.test.UserImpl">
<property name="name" value="#{obj.vale}" />
<property name="age" value="#{obj.method()}" />
</bean>
6.Spring集合类型注入
<!-- 注入集合类型,属性value,对象 ref -->
<bean id="collectionBean" class="pers.zx.sprint.test.CollectionBean">
<!-- 数组类型 -->
<property name="arrs">
<list>
<value>aa</value>
<value>bb</value>
<value>cc</value>
</list>
</property>
<!-- 注入list集合 -->
<property name="list">
<list>
<value>aa</value>
<value>bb</value>
<value>cc</value>
</list>
</property>
<!-- 注入set集合 -->
<property name="set">
<set>
<value>aaa</value>
<value>bbb</value>
<value>ccc</value>
</set>
</property>
<!-- 注入Map集合 -->
<property name="map">
<map>
<entry key="aaa" value="111"/>
<entry key="bbb" value="222"/>
<entry key="ccc" value="333"/>
</map>
</property>
</bean>
在具体collectionBean类中要有相应的set方法。而要获取值的时候相应的类中要有get方法。
六、Spring分模块开发
1.一次加载多个配置文件
2.在一个配置文件中引入多个
注意:在编写dao时如何用service调用它,就可以将dao和service层的实现类放到spring中,然后将dao注入到service中。此时就可以直接在service中调用dao中的方法了,不用在service中getBean
七、如何解决Spring的工厂每次都创建
八、Spring IoC注解的方式
1.示例
(1)spring4中,除了基础包还需要引入aop的jar包
(2)创建applicationContext.xml,为其引入约束
将下面这段代码添加到xml中
(3)创建接口和实现类
public interface User {
public void test();
}
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("User")
public class UserImpl implements User {
@Value("zx")
private String name;
public void test() {
// TODO Auto-generated method stub
System.out.println("使用注解的方式"+name);
}
}
注意:
@Component(“user”) //相当于< bean name=”user” class=”pers.zx.spring.test.UserImpl” >
@Value(“zx”)//< property name=”name” value=”zx” />此时不用setName方法
(4)配置xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here -->
<!-- spring的IOC的注解的入门 -->
<!-- 配置组件扫描,扫描使用IOC的注解的类 -->
<context:component-scan base-package="pers.zx.spring.test" />
</beans>
(5)test方法
@Test
public void test() {
ApplicationContext a=new ClassPathXmlApplicationContext("applicationContext.xml");
User user=(User)a.getBean("user");
user.test();
}
}
2.Spring IoC注解详解
(1)@Component:组件
修饰一个类,将这个类交给Spring管理
这个注解有三个衍生的注解,和component功能类似
1.@Controler:修饰web层
2.@Service:修饰service层
3.@Repository:修饰dao层
(2)属性注入的注解
1.普通属性
@Value:设置普通属性的值
2.对象类型属性
(1)Autowired:按照对象的类型来设置属性的值完成注入,即不管上面三种注解的名称与这个是否一样,都可以运行。
@Qualifier:和@Autowired一起完成按照名称进行属性值的设置
@Autowired
@Qualifier(value=”user”)(2)@Resource:完成对象类型的属性的注入,按照名称来完成属性注入的。
@Resource(name=”user”)
(3)Bean的其他注解
1.生命周期相关的注解
@PostConstruce:初始化方法
@PreDestroy:销毁方法
在相应的方法上面加这些注解2.Bean作用范围的注解
@Scope
@Scope(“prototype”)
3.XML配置与注解的比较
(1)适用场景
XML:可以适用任何场景
好处:结构清晰,方便维护
注解:有些对方用不了,比如某个类不是自己提供的。
好处:开发迅速方便。
(2)XML与注解整合开发
就是取双方的优点整合到一起
XML:配置Bean
注解:配置属性
由于在纯xml中注入属性需要set方法,这里用注解的话就不需要set方法了,需要到xml里配置< context:annotation-config/>,取代原先扫描包的标签。
注意:在XML注入时,被注入的属性或对象都要设置set方法。
九、Spring AOP概述
AOP(Aspect Oriented Programming),,面向切面编程。通过预编译方式和运行期动态代理实现程序功能的统一维护的技术。它是OOP(面向对象编程)的扩展和延申,主要是为了解决OOP开发遇到的问题。
看一个图来了解以下AOP:
AOP的优点:
在不修改源代码的情况下对程序进行增强
AOP可以进行权限校验,日志记录,性能监控,事务控制
1.Spring底层的AOP实现原理
动态代理
JDK动态代理:只能对实现了接口的类产生代理
Cglib动态代理:对没有实现接口的类产生代理对象,生成子类对象
2.JDK动态代理实现
(1)创建User类和UserImpl实现类
User.class
package pers.zx.aop.proxy;
public interface User {
public void save();
public void add();
}
UserImpl.class
package pers.zx.aop.proxy;
public class UserImpl implements User{
public void save() {
// TODO Auto-generated method stub
System.out.println("save被调用");
}
public void add() {
// TODO Auto-generated method stub
System.out.println("add被调用");
}
}
(2)创建动态代理类
package pers.zx.aop.proxy;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Proxy;
public class UserProxy implements org.springframework.cglib.proxy.InvocationHandler {
private User user;
public UserProxy(User user) {
this.user=user;
}
public UserProxy() {
// TODO Auto-generated constructor stub
}
public User createProxy() {
User userProxy=(User)Proxy.newProxyInstance(user.getClass().getClassLoader(),
user.getClass().getInterfaces(),new UserProxy(user));//创建user的代理
return userProxy;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if("save".equals(method.getName())) {
System.out.println("proxy");
return method.invoke(user, args);
}
return method.invoke(user, args);
}
}
(3)测试类
package pers.zx.aop.proxy;
import org.junit.Test;
public class TestOfProxy {
@Test
public void test() {
User user=new UserImpl();
User p=new UserProxy(user).createProxy();//创建user的代理
p.save();
p.add();
}
}
3.cglib动态代理
(1)编写CustomerDao
package pers.zx.aop.cglib;
public class CustomerDao {
public void save() {
System.out.println("save被调用");
}
public void add() {
System.out.println("add被调用");
}
}
(2)编写代理类
package pers.zx.aop.cglib;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
public class CglibProxy implements MethodInterceptor {
private CustomerDao customerDao;
public CglibProxy(CustomerDao customerDao) {
this.customerDao=customerDao;
}
public CustomerDao createProxy() {
//1.创建cglib的核心类对象
Enhancer enhancer=new Enhancer();
//2.设置父类
enhancer.setSuperclass(customerDao.getClass());
//3.设置回调,类似于InvocationHandler对象
enhancer.setCallback(this);//或者new CglibProxy(customerDao);
//4.创建代理对象
CustomerDao proxy=(CustomerDao)enhancer.create();
return proxy;
}
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if("save".equals(method.getName())) {
System.out.println("proxy");
return methodProxy.invokeSuper(proxy, args);
}
return methodProxy.invokeSuper(proxy, args);
}
}
(3)编写测试类
package pers.zx.aop.cglib;
import org.junit.Test;
public class ProxyTest {
@Test
public void test() {
CustomerDao c=new CustomerDao();
CustomerDao u=new CglibProxy(c).createProxy();
u.save();
u.add();
}
}
十、Spring Aop开发(AspectJ的XML方式)
AspectJ是一种面向切面编程的框架。
1.AOP术语
2.AspectJ 示例
(1)添加jar包,我们在Spring整合Jutils单元测试的时候要引入spring-test-4.2.4.RELEASE,这样就可以和方便的测试,不用每次都创建工厂了,通过注解的方式,在测试类中可以看到
(2)在src下创建application.xml,并添加约束
(3)编写User接口和UserImpl实现类
package pers.zx.AspectJ.test;
public interface User {
public void save();
public void add();
}
package pers.zx.AspectJ.test;
public class UserImpl implements User{
public void save() {
// TODO Auto-generated method stub
System.out.println("save被调用");
}
public void add() {
// TODO Auto-generated method stub
System.out.println("add被调用");
}
}
(4)编写切入类
package pers.zx.AspectJ.test;
public class XMLAspectJ {
public void check() {
System.out.println("Check");
}
}
(5)配置xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->
<!-- 配置目标对象:被增强的对象 -->
<bean id="user" class="pers.zx.AspectJ.test.UserImpl"/>
<!-- 将切面类交给Spring管理 -->
<bean id="aspectj" class="pers.zx.AspectJ.test.XMLAspectJ"/>
<!-- 通过AOP的配置完成对目标类产生代理 -->
<aop:config>
<!-- 通过表达式配置那些类的那些方法需要进行增强 ,..是可变参数,*是任意返回值-->
<aop:pointcut expression="execution(* pers.zx.AspectJ.test.UserImpl.save(..))" id="pointcut_save"/>
<!-- 配置切面 -->
<aop:aspect ref="aspectj">
<!-- 在配置方法之前调用 -->
<aop:before method="check" pointcut-ref="pointcut_save"/>
</aop:aspect>
</aop:config>
</beans>
(6)编写测试类(Spring整合Jutils测试)
package pers.zx.AspectJ.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
//Spring 整合Jutil单元测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AspectjTest {
@Autowired
@Qualifier(value="user")
private User user;
@Test
public void test() {
user.save();
user.add();
}
}
3.Spring中的通知类型
(1)前置通知
在目标方法执行前进行的操作,可以获得切入点的信息
(2)后置通知
在目标方法之后进行的操作,可以获得方法的返回值
(3)环绕通知
在目标方法执行前和执行后进行的操作,可以阻止目标方法的执行
(4)异常抛出通知
当所配置的方法有异常了会执行的操作,可以抛出异常类型
(5)最终通知
不管方法有没有异常,只要配置了都要执行,相当于finall块中的语句
切入类代码:
package pers.zx.AspectJ.test;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
public class XMLAspectJ {
//前置通知:并获得切入点信息
public void before(JoinPoint joinPoint) {
System.out.println("Check "+joinPoint);
}
//后置通知:并获取配置方法的返回值
public void behind(Object result) {
System.out.println("Behind "+result);
}
//环绕通知
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("around before");
Object obj=joinPoint.proceed();
System.out.println("around behind");
return obj;
}
//异常抛出通知
public void throwsEx(Throwable ex) {
System.out.println("throws exception"+ex);
int i=1/0;
}
//最终通知
public void end() {
System.out.println("end");
}
}
配置文件代码:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->
<!-- 配置目标对象:被增强的对象 -->
<bean id="user" class="pers.zx.AspectJ.test.UserImpl"/>
<!-- 将切面类交给Spring管理 -->
<bean id="aspectj" class="pers.zx.AspectJ.test.XMLAspectJ"/>
<!-- 通过AOP的配置完成对目标类产生代理 -->
<aop:config>
<!-- 通过表达式配置那些类的那些方法需要进行增强 ,..是可变参数,*是任意返回值-->
<aop:pointcut expression="execution(* pers.zx.AspectJ.test.UserImpl.before(..))" id="pointcut_before"/>
<aop:pointcut expression="execution(* pers.zx.AspectJ.test.UserImpl.behind(..))" id="pointcut_behind"/>
<aop:pointcut expression="execution(* pers.zx.AspectJ.test.UserImpl.around(..))" id="pointcut_around"/>
<aop:pointcut expression="execution(* pers.zx.AspectJ.test.UserImpl.throwsEx(..))" id="pointcut_throwsEx"/>
<aop:pointcut expression="execution(* pers.zx.AspectJ.test.UserImpl.end(..))" id="pointcut_end"/>
<!-- 配置切面 -->
<aop:aspect ref="aspectj">
<!-- 前置通知:在配置方法之前调用 -->
<aop:before method="before" pointcut-ref="pointcut_before"/>
<!-- 后置通知 :返回结果result-->
<aop:after-returning method="behind" pointcut-ref="pointcut_behind" returning="result"/>
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="pointcut_around"/>
<!-- 异常抛出通知:抛出异常ex -->
<aop:after-throwing method="throwsEx" pointcut-ref="pointcut_throwsEx" throwing="ex"/>
<!-- 最终通知 :相当于finall块中的语句-->
<aop:after method="end" pointcut-ref="pointcut_end"/>
</aop:aspect>
</aop:config>
</beans>
测试类:
package pers.zx.AspectJ.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
//Spring 整合Jutil单元测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AspectjTest {
@Autowired
@Qualifier(value="user")
private User user;
@Test
public void test() {
user.before();
user.behind();
user.around();
user.throwsEx();
user.end();
}
}
User接口与UserImpl.class:
package pers.zx.AspectJ.test;
public interface User {
public void before();
public int behind();
public void around();
public void throwsEx();
public void end();
}
///////////////////////////
package pers.zx.AspectJ.test;
public class UserImpl implements User{
public void before() {
// TODO Auto-generated method stub
System.out.println("before被调用");
}
public int behind() {
// TODO Auto-generated method stub
System.out.println("behind被调用");
return 10;
}
public void around() {
// TODO Auto-generated method stub
System.out.println("around被调用");
}
public void throwsEx() {
// TODO Auto-generated method stub
System.out.println("throwsEx被调用");
}
public void end() {
// TODO Auto-generated method stub
System.out.println("end被调用");
}
}
4.切入点表达式语法
基于execution()函数来完成
语法:
[访问控制修饰符] 方法的返回值类型 包名.类名.方法名(参数)
(1) 代表任意方法的返回值类型 、包名、类名、方法名。
public pers.zx.spring.test.clazz.method(); //任意方法的返回值类型(2) .. 放在参数中代表任意个数参数,放在类名后面是其任意子类,包后面就是任意子包
public pers.zx.spring.test.clazz.method(..); //代表任意个数参数
public pers.zx.test..*.method(..);//test的所有子包下的所有类的method方法(3) + 表示本类和其子类
public * pers.zx.test.User+.metnod(..);//user及其子类下面的method方法
十一、Spring AOP开发(基于AspectJ注解的开发)
1.示例
(1)创建项目,添加jar包
(2)在src下创建applicationContext.xml,并引入约束
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
</beans>
(3)编写User类
package pers.zx.spring.ann;
public class User {
public void save() {
System.out.println("save被调用");
}
public void add() {
System.out.println("add被调用");
}
}
(4)编写切面类
package pers.zx.spring.ann;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
//为切面类配置注解
@Aspect
public class AspectAnn {
@Before(value="execution(* pers.zx.spring.ann.User.save(..))")
public void before() {
System.out.println("before");
}
}
(5)配置xml文件
<!-- 在配置文件中开启注解的AOP的开发============ -->
<aop:aspectj-autoproxy/>
<!-- 配置目标类================ -->
<bean id="user" class="pers.zx.spring.ann.User">
</bean>
<!-- 配置切面类================ -->
<bean id="aspectAnn" class="pers.zx.spring.ann.AspectAnn" >
(6)编写测试类
package pers.zx.spring.ann;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AspetcJTest {
@Autowired
@Qualifier(value="user")
private User user;
@Test
public void test() {
user.save();
user.add();
}
}
2.Spring注解的AOP通知类型
(1)前置通知
(2)后置通知
(3)环绕通知
(4)异常通知
(5)最终通知
3.Spring注解的AOP切入点
为了不用给每个通知都配相同方法,可以设置切入点,在用到改方法的地方引入切入点就可以了。
@Before(value="AspectAnn.pointcut()")
public void before() {
System.out.println("before");
}
//save切入点,以后所有使用save方法的通知都可以直接 类名.pointcut()来调用 @Pointcut(value="execution(* pers.zx.spring.ann.User.save(..))")
private void pointcut(){}
十二、spring JDBC模板
Spring是EE开发的一站式的框架,有EE开发的每层的解决方案。Spring对持久层也提供了解决方案:ORM模块和JDBC的模板。
Spring提供了很多的模板用于简化开发:
1.JDBC模板示例
(1)引入jar包
(2)创建数据库
(3)编写测试类
package pers.zx.spring.jdbc;
import org.junit.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import com.mchange.v2.c3p0.DriverManagerDataSource;
public class JdbcDemo01 {
@Test
//jdbc模板的使用类似于Dbutils
public void JdbcTest() {
//创建连接池
DriverManagerDataSource dataSource=new DriverManagerDataSource();
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql:///zx");
dataSource.setUser("root");
dataSource.setPassword("*****");
//创建Jbdc模板对象
JdbcTemplate jdbc=new JdbcTemplate(dataSource);
jdbc.update("insert into user values(null,?,?)", "zx",20);
}
}
2.将Jdbc模板和连接池都交给spring管理(IoC)
(1)添加applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 配置Spring内置连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.DriverManagerDataSource">
<!-- 属性注入 -->
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///zx"/>
<property name="user" value="root"/>
<property name="password" value="****"/>
</bean>
<!-- 配置Spring JDBC的模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
(2)编写测试类
package pers.zx.spring.jdbc;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class JdbcDemo02 {
@Autowired
@Qualifier(value="jdbcTemplate")
private JdbcTemplate jdbcTemplate;
@Test
public void test() {
jdbcTemplate.update("insert into user values(null,?,?)", "zxx",20);
}
}
3.DBCP连接池的使用
(1)引入jar包
com.springsource.org.apache.commons.dbcp-1.2.2.osgi
com.springsource.org.apache.commons.pool-1.5.3
(2)配置applicationContext.xml
<!--配置DBCP连接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<!-- 属性注入 -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///zx"/>
<property name="username" value="root"/>
<property name="password" value="19960213zx"/>
</bean>
<!-- 配置Spring JDBC的模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 注入DriverManagerDataSource 类-->
<property name="dataSource" ref="dataSource"></property>
</bean>
4.C3P0连接池使用
(1)引入jar包
com.springsource.com.mchange.v2.c3p0-0.9.1.2
(2)配置applicationContext.xml
<!-- 配置C3P0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///zx"/>
<property name="user" value="root"/>
<property name="password" value="19960213zx"/>
</bean>
<!-- 配置Spring JDBC的模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 注入DriverManagerDataSource 类-->
<property name="dataSource" ref="dataSource"></property>
</bean>
5.JDBC模板使用外部引入的属性文件
(1)jdbc.properties
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///zx
jdbc.username=root
jdbc.password=*****
(2)在applicationContext.xml配置属性文件
①.第一种
<!-- 引入bean标签来引入配置文件(很少使用) -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties"></property>
</bean>
<!-- 配置C3P0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 配置Spring JDBC的模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 注入DriverManagerDataSource 类-->
<property name="dataSource" ref="dataSource"></property>
</bean>
②.第二种
<!-- context标签引入 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置C3P0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 配置Spring JDBC的模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 注入DriverManagerDataSource 类-->
<property name="dataSource" ref="dataSource"></property>
</bean>
6.使用JDBC的模板完成CRUD操作
public class JdbcDemo2 {
@Resource(name="jdbcTemplate")
private JdbcTemplate jdbcTemplate;
@Test
// 保存操作
public void demo1(){
jdbcTemplate.update("insert into account values (null,?,?)", "kk",23);
}
@Test
// 修改操作
public void demo2(){
jdbcTemplate.update("update account set name = ? ,money = ? where id = ?", "ll",12,6);
}
@Test
// 删除操作
public void demo3(){
jdbcTemplate.update("delete from account where id = ?", 6);
}
@Test
// 查询操作:
public void demo4(){
String name = jdbcTemplate.queryForObject("select name from account where id = ?", String.class, 5);
System.out.println(name);
}
@Test
// 统计查询
public void demo5(){
Long count = jdbcTemplate.queryForObject("select count(*) from account", Long.class);
System.out.println(count);
}
@Test
// 封装到一个对象中
public void demo6(){
Account account = jdbcTemplate.queryForObject("select * from account where id = ?", new MyRowMapper(), 5);
System.out.println(account);
}
@Test
// 查询多条记录
public void demo7(){
List<Account> list = jdbcTemplate.query("select * from account", new MyRowMapper());
for (Account account : list) {
System.out.println(account);
}
}
class MyRowMapper implements RowMapper<Account>{
@Override
public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
Account account = new Account();
account.setId(rs.getInt("id"));
account.setName(rs.getString("name"));
account.setMoney(rs.getDouble("money"));
return account;
}
}
}
十三、Spring事务管理
1.事务的回顾
(1)事务:逻辑上的一组操作,组成这组操作的各个单元,要么全都成功,要么全都失败。
(2)事务的特性
(3)不考虑隔离性会引发的安全性问题
(4)事务的隔离级别
2.Spring事务管理的API
(1)PlatformTransactionManager:平台事务管理器
(2)TransactionDefinition :事务定义信息
(3)TransactionStatus:事务的状态
事务管理的API的关系:
Spring进行事务管理的时候,首先平台事务管理器根据事务定义信息进行事务的管理,在事务管理过程中,会产生各种状态,将这些状态的信息记录到事务状态的对象中。
3.Spring事务传播
主要用来解决业务层方法互相调用的问题。
4.编程式事务管理
AccountDao&AccountDaoImpl
// 转账的DAO的接口
public interface AccountDao {
public void outMoney(String from ,Double money);
public void inMoney(String to ,Double money);
}
///////////////////////////////////
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
@Override
public void outMoney(String from, Double money) {
this.getJdbcTemplate().update("update account set money = money - ? where name = ?", money,from);
}
@Override
public void inMoney(String to, Double money) {
this.getJdbcTemplate().update("update account set money = money + ? where name = ?", money ,to);
}
}
AccountService&AccountServiceImpl
public interface AccountService {
public void transfer(String from,String to,Double money);
}
/////////////////////////////////////////
public class AccountServiceImpl implements AccountService {
// 注入DAO:
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
// 注入事务管理的模板
private TransactionTemplate trsactionTemplate;
public void setTrsactionTemplate(TransactionTemplate trsactionTemplate) {
this.trsactionTemplate = trsactionTemplate;
}
@Override
// from:转出账号
//to:转入账号
//money:转账金额
public void transfer(final String from, final String to, final Double money) {
trsactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
accountDao.outMoney(from, money);
int d = 1/0;
accountDao.inMoney(to, money);
}
});
}
}
applicationContext.xml
<!-- 配置Service============= -->
<bean id="accountService" class="pers.zx.spring.test.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
<!-- 注入 事务管理的模板 -->
<property name="trsactionTemplate" ref="transactionTemplate"/>
</bean>
<!-- 配置DAO================= -->
<bean id="accountDao" class="pers.zx.spring.test.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置连接池和JDBC的模板 -->
<!-- 第二种方式通过context标签引入的 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置C3P0连接池=============================== -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 配置平台事务管理器============================= -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置事务管理的模板 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
</bean>
配置事务管理器,然后将数据库连接池注入到其中,然后配置事务管理模板,将事务管理器注入到其中,最后由于是在service层中进行事务管理,所以要将事务管理模板注入到service中。
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:tx.xml")
public class SpringDemo1 {
@Resource(name="accountService")
private AccountService accountService;
@Test
public void demo1(){
accountService.transfer("zx", "zxx", 1);
}
}
5.声明式事务管理 XML方式———AOP思想
(1)配置applicationContext.xml
<!-- 配置Service============= -->
<bean id="accountService" class="com.itheima.tx.demo2.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
<!-- 配置DAO================= -->
<bean id="accountDao" class="com.itheima.tx.demo2.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置连接池和JDBC的模板 -->
<!-- 第二种方式通过context标签引入的 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置C3P0连接池=============================== -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 配置事务管理器=============================== -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置事务的增强=============================== -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 事务管理的规则 -->
<!-- <tx:method name="save*" propagation="REQUIRED" isolation="DEFAULT"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="find*" read-only="true"/> -->
<tx:method name="*" propagation="REQUIRED" read-only="false"/>
</tx:attributes>
</tx:advice>
<!-- aop的配置 -->
<aop:config>
<aop:pointcut expression="execution(* com.itheima.tx.demo2.AccountServiceImpl.*(..))" id="pointcut1"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
</aop:config>
其他类保持去掉原先事务的状态就可以了,这里为transfer方法添加了事务。
6.声明式事务管理 注解方式
(1)配置applicationContext.xml
<!-- 配置Service============= -->
<bean id="accountService" class="com.itheima.tx.demo3.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
<!-- 配置DAO================= -->
<bean id="accountDao" class="com.itheima.tx.demo3.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置连接池和JDBC的模板 -->
<!-- 第二种方式通过context标签引入的 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置C3P0连接池=============================== -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 配置事务管理器=============================== -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 开启注解事务================================ -->
<tx:annotation-driven transaction-manager="transactionManager"/>
需要配置事务管理器以及开启事务,之后去相应的service类上去配置@Transactional
(2)@Transactional