一、Spring的概述
- 什么是Spring
Spring是一个开源框架,Spring是于2003年兴起的一个轻量级的java开发框架,简单来说,Spring是一个分层的java SE/EE一站式轻量级开源框架。
一站式框架:有EE开发的每一层解决方案
web层:SpringMVC
Service层:Spring的Bean管理,Spring声明式事务
Dao层:Spring的jdbc模板,Spring的ORM模板 - Spring的版本
Spring3.X和Spring4.X
二、Spring的IOC
- Spring的入门(IOC)
什么是IOC
IOC:Inversion of Control(控制反转),将对象的创建权反转给Spring
Spring的开发包
解压后是如下目录
docs: Spring的开发规范和API
libs: Spring的开发的jar和源码
schema: Spring的配置文件的约束 - 创建web项目,引入jar包
- 对于IOC的理解,我认为是在java中免去了实例化对象(new 类名)的步骤,把这一步转交给了一个xml配置文件(就是交给Spring),具体步骤如下。
- 创建一个接口UserDAO,并且创建类UserDAOImpl实现该接口。
- 在src文件夹里面创建一个applicationContext.xml文件。这个文件就是要配置类对象。在Spring的解压路径下spring-framework-4.2.4.RELEASE\docs\spring-framework-reference\html\xsd-configuration.html导入下列代码。
<?xml version="1.0" encoding="UTF-8"?>
<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">
</beans>
在这个xml文件中的中加入以下代码,注意这个userDAO的id,以及class属性中选中的是UserDAOImpl类。
<bean id="userDAO" class="com.zjw.spring.spring01.impl.UserDAOImpl"></bean>
- 编写测试类,注意测试类中的getBean函数的参数userDAO,对应的是xml中的id,所以创建的是UserDAOImpl的对象。
- 现在是有类的实例化对象了,但是对象的属性能不能也写在配置文件中?
这就需要引入DI的概念,DI,依赖注入,前提是必须有IOC的环境,Spring管理这个类的时候将类的依赖的属性注入(设置)进来。
现在在UserDAOImpl类中加入一个属性name,创建name属性的setName。
在配置文件xml中还要加入属性,在原来的标签中加入标签,该标签是在对象中加入值为“郑经纬”的name属性。这样在测试类中创建UserDAOImpl的对象时,对象就会带有该name属性,执行结果如下。
<!--spring的入门配置-->
<bean id="userDAO" class="com.zjw.spring.spring01.impl.UserDAOImpl">
<property name="name" value="郑经纬"></property>
</bean>
- Bean标签中有id和name的配置
id:使用了约束中的唯一约束,里面不能出现特殊字符的。
name:并非使用约束中的唯一约束。(理论上可以出现重复的,但是实际开发不能出现的)里面可以出现特殊字符。 - Bean的生命周期的配置
init-method:Bean被初始化的时候执行的方法
destroy-method:Bean被销毁的时候执行的方法
<!--Spring的Bean生命周期的配置,其中的scope是作用范围,作用范围默认是单例模式-->
<bean id="customerDAO" class="com.zjw.spring.spring01.impl.CustomerDAOImpl" scope="singleton" init-method="setup" destroy-method="destory"></bean>
- Bean的作用范围的配置
scope:Bean的作用范围
- singleton:默认的,Spring会采用单例模式创建这个对象,在单例模式下,创建的对象都是同一个,无论是创建几个对象,其地址都是相同的。创建多个对象只会触发一次init-method函数。
- prototype:多例模式,创建的多个对象其地址都不一样,而且每创建一次对象,都会触发init-method函数。
- request:应用在web项目中,Spring创建这个类以后,将这个类存入到request范围中。
- session:应用在web项目中,Spring创建这个类以后,将这个类存入到session范围内。
- globalsession :应用在web项目中,必须在porlet环境下使用。但是如果没有这种环境,相对于session。
- Spring的属性注入
构造函数的方式的属性注入
创建Car类,在Car类中有两个name和price属性,并且有构造函数
xml文件的配置,并不是使用set方法创建属性时的标签,而是使用标签,用法都差不多,只是标签不一样,set方法属性赋值使用,构造方法属性赋值使用。
<!--Spring的属性注入方式-->
<!--构造方法方式-->
<bean id="car" class="com.zjw.spring.spring01.domain.Car">
<constructor-arg name="name" value="陆地巡洋舰"></constructor-arg>
<constructor-arg name="price" value="800000"></constructor-arg>
</bean>
set函数的方式的属性注入
普通属性注入:
<!--set方法的方式-->
<bean id="car02" class="com.zjw.spring.spring01.domain.Car02">
<property name="name" value="普拉多"/>
<property name="price" value="700000"/>
</bean>
对象类型属性的注入,注意ref属性:
<!--set方法注入对象类型的属性-->
<bean id="employee" class="com.zjw.spring.spring01.domain.Employee">
<!--value:设置普通类型的值, ref设置其他的类的id或name-->
<property name="name" value="憨憨"/>
<property name="car02" ref="car02"/>
</bean>
P名称空间的属性注入(Spring2.5以后)
通过引入p名称空间完成属性的注入,在原来xml文件中加入这一句:
普通属性 p:属性名=“值”
<bean id="car02" class="com.zjw.spring.spring01.domain.Car02" p:name="帕拉梅拉" p:price="3000000"></bean>
对象属性 p:属性名-ref=“值”
<bean id="employee" class="com.zjw.spring.spring01.domain.Employee" p:name="信球" p:car02-ref="car02"></bean>
SqEL的属性注入(Spring3.0以后)
SpEL:Spring Expression Language,Spring的表达式语言。在中括号中可以添加字符串,表达式,对象,函数等
用法:#{SqEL}
<!--SpEL的注入方式-->
<bean id="carInfo" class="com.zjw.spring.spring01.domain.CarInfo"></bean>
<bean id="car02" class="com.zjw.spring.spring01.domain.Car02">
<property name="name" value="#{carInfo.getName()}"/>
<property name="price" value="#{carInfo.calculatorPrice()}"/>
</bean>
<bean id="employee" class="com.zjw.spring.spring01.domain.Employee">
<property name="name" value="#{'一男'}"/>
<property name="car02" value="#{car02}"/>
<!--引用对象不加单引号-->
</bean>
集合类型的属性注入
<!--Spring的集合属性的注入-->
<!--注入数组类型-->
<bean id="collectionBean" class="com.zjw.spring.spring01.domain.CollectionBean">
<!--数组类型-->
<property name="arrs">
<list>
<value>王东</value>
<value>铁憨憨</value>
<value>信球</value>
</list>
</property>
<!--注入list的类型-->
<property name="list">
<list>
<value>诸葛亮</value>
<value>孙伯符</value>
<value>黄月英</value>
</list>
</property>
<property name="set">
<set>
<value>aaa</value>
<value>ccc</value>
<value>sss</value>
</set>
</property>
<property name="map">
<map>
<entry key="aaa" value="111"></entry>
<entry key="sss" value="222"></entry>
<entry key="ccc" value="233"></entry>
</map>
</property>
</bean>
- Spring的分模块开发的配置
分模块配置,在加载配置文件的时候,在一个配置文件中引入多个配置文件
三、Spring的基于IOC的注解开发
- 注解开发
就是承接上一部分的xml配置,使用注解代替xml文件把类交给Spring管理,在使用注解开发之前,需要在原来的jar包中再添加一个aop的包,
- 引入相关配置文件
引入约束,在Spring的解压路径下spring-framework-4.2.4.RELEASE\docs\spring-framework-reference\html\xsd-configuration.html导入下列代码。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
</beans>
- 编写相关的类
编写UserDao接口和UserDaoImpl类。
- 配置注解扫描
注解扫描,是让Spring知道在哪个类里面有注解。
<!--Spring的IOC的注解的入门 -->
<!--使用IOC的注解开发,配置组件扫描-->
<!--扫描是为了扫描类上的注解-->
<context:component-scan base-package="com.zjw.spring.spring02"/>
- 在相关的类上添加注解
在UserDaoImpl类上添加注解@Component(“userDao”)
@Component("userDao") //相当于<bean id="userDao" class="com.zjw.spring.spring02.impl.UserDaoImpl" />
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("dao中保存用户的方法执行了。。。");
}
}
-
Spring的Bean管理中常用的注解
@Component注解(作用在类上)
属性注入的注解:(使用注解注入的方式,可以不用提供 set 方法.)
-
Bean的生命周期和作用范围的注解
@Scope:
- singleton:单例
- prototype:多例
@PostConstruct :相当于 init-method
@PreDestroy :相当于 destroy-method
- Sping的Bean管理的方式的比较
XML 和注解:
- XML :结构清晰.
- 注解 :开发方便.(属性注入.)
实际开发中还有一种 XML 和注解整合开发:
- Bean 有 XML 配置.但是使用的属性使用注解注入.
- 当使用这种XML配置类,注解配置属性注入时,可以把那个扫描标签改了,改成只扫描属性
<!--在没有扫描的情况下,使用属性注入的注解:@Resource @Autowired @Qualifier-->
<context:annotation-config></context:annotation-config>
四、Spring的AOP开发
aop面向切面编程,可以对程序增强,在不修改源码的情况下,AOP可以进行权限校验,日志记录,性能监控,事务控制,就是在不改变源码的情况下添加新的功能。
AOP思想最早是由AOP联盟的组织提出,制定了一套规范,在切面编程这一块,AspectJ做得最好,所以Spring将AOP思想,也就是AspectJ技术引入到了框架中,而且还遵守AOP的规范。
AOP底层实现是代理机制, Spring 的 AOP 的底层用到两种代理机制:
- JDK 的动态代理 :针对实现了接口的类产生代理.
- Cglib 的动态代理 :针对没有实现接口的类产生代理. 应用的是底层的字节码增强的技术 生成当前类
的子类对象.
- JDK代理实现(JDK代理是必须要有接口的)
步骤一:创建一个UserDaoImpl02类和接口类UserDao02
package com.zjw.spring.spring02;
public interface UserDao02 {
public void save();
public void update();
public void find();
public void delete();
}
=====================分割线=====================================
package com.zjw.spring.spring02.impl;
import com.zjw.spring.spring02.UserDao02;
public class UserDaoImpl02 implements UserDao02 {
@Override
public void save() {
System.out.println("保存用户...");
}
@Override
public void update() {
System.out.println("更新用户....");
}
@Override
public void find() {
System.out.println("查找用户....");
}
@Override
public void delete() {
System.out.println("删除用户....");
}
}
步骤二:在JdkProxy类中编写产生代理的函数。
package com.zjw.spring.spring02.Proxy;
import com.zjw.spring.spring02.UserDao02;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxy implements InvocationHandler {
private UserDao02 userDao02;
public JdkProxy(UserDao02 userDao02){
this.userDao02 = userDao02;
}
//产生userdao代理的方法
public UserDao02 createProxy(){
UserDao02 userDao02Proxy = (UserDao02) Proxy.newProxyInstance(userDao02.getClass().getClassLoader(),
userDao02.getClass().getInterfaces(),this);
return userDao02Proxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//判断方法名是不是save
if ("save".equals(method.getName())){
//增强
System.out.println("权限校验==================================");
return method.invoke(userDao02,args);
}
return method.invoke(userDao02,args);
}
}
步骤三:测试
@org.junit.Test
public void demo06(){
UserDao02 userDao02 = new UserDaoImpl02();
//创建代理
UserDao02 proxy = new JdkProxy(userDao02).createProxy();
proxy.delete();
proxy.find();
proxy.save();
proxy.update();
}
- Cglib代理实现(可以不要接口)
步骤一:创建目标类CustomerDao
package com.zjw.spring.spring02.dao;
public class CustomerDao {
public void save(){
System.out.println("保存客户。。。。。");
}
public void update(){
System.out.println("更新客户。。。。。");
}
public void delete(){
System.out.println("删除客户。。。。。");
}
public void find(){
System.out.println("查找客户。。。。。");
}
}
步骤二:在CglibProxy类中编写代理类
package com.zjw.spring.spring02.Proxy;
import com.zjw.spring.spring01.CustomerDAO;
import com.zjw.spring.spring02.dao.CustomerDao;
import com.zjw.spring.spring02.impl.CustomerService;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxy implements MethodInterceptor{
private CustomerDao customerDao;
public CglibProxy(CustomerDao customerDao){
this.customerDao = customerDao;
}
//使用Cglib产生代理的方法
public CustomerDao createProxy(){
//1.创建cglib的核心类对象
Enhancer enhancer = new Enhancer();
//2.设置父类
enhancer.setSuperclass(customerDao.getClass());
//3.设置回调(类似与InvocationHandler对象)
enhancer.setCallback(this);
//4.创建代理对象
CustomerDao proxy = (CustomerDao) enhancer.create();
return proxy;
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)
throws Throwable {
//判断方法是否为save
if ("save".equals(method.getName())){
//增强
System.out.println("权限校验===================");
return methodProxy.invokeSuper(proxy,args);
}
return methodProxy.invokeSuper(proxy,args);
}
}
步骤三:编写测试
@org.junit.Test
public void demo07(){
CustomerDao customerDao = new CustomerDao();
CustomerDao proxy = new CglibProxy(customerDao).createProxy();
proxy.save();
proxy.delete();
proxy.find();
proxy.update();
}
- Sping下的代理机制,基于AspectJ的AOP开发
AOP开发中的相关术语
- Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点.
- Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义.
- Advice(通知/增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
- Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方法或 Field.
- Target(目标对象):代理的目标对象
- Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程.
- spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装在期织入
- Proxy(代理):一个类被 AOP 织入增强后,就产生一个结果代理类
- Aspect(切面): 是切入点和通知(引介)的结合
引入jar包
另外,要AOP开发,还需要引入一些包,要引入AOP联盟的包,还有AspectJ的包,还有一个Spring本身对于AOP开发搞的包。
- 实现Spring的AOP开发
步骤一:编写一个目标类,就是要增强的类ProductDaoImpl和他的接口类ProudctDao类,在Spring代理中,目标类要是有接口,底层就用JDK代理,否则就用Cglib
package com.zjw.spring.spring02;
public interface ProductDao {
public void save();
public void find();
public String update();
public String delete();
}
===================分割线==========================================================
package com.zjw.spring.spring02.impl;
import com.zjw.spring.spring02.ProductDao;
public class ProductDaoImpl implements ProductDao {
@Override
public void save() {
System.out.println("保存商品。。。");
}
@Override
public void find() {
System.out.println("查找商品。。。");
// int i = 1 / 0;//这句是为了让目标函数抛出异常,除0的异常
}
@Override
public String update() {
System.out.println("更新商品。。。");
return "二贝";
}
@Override
public String delete() {
System.out.println("删除商品。。。");
return "铁憨憨";
}
}
步骤二:编写MyAspectXML类(切面类),里面存放增强函数
package com.zjw.spring.spring02.Proxy;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
//切面类
public class MyAspectXML {
//前置通知,在指定函数执行前执行
public void checkPri(JoinPoint joinPoint){
System.out.println("权限校验==============="+joinPoint);
}
//后置记录,在指定函数执行后执行,可以获取目标函数的返回值
public void writeLog(Object result){
System.out.println("日至记录======================"+result);
}
//环绕通知,在指定函数执行前后执行,同样可以获取目标函数的返回值
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前通知==================");
Object obj = joinPoint.proceed();//这是执行目标代码,obj是目标函数的返回值,这行代码相当于调用目标函数
System.out.println("环绕后通知===================="+obj);
return obj;
}
//异常抛出通知,当目标函发生异常时执行,没有异常发生不执行
public void afterThrowing(Throwable ex){
System.out.println("异常抛出通知============" + ex.getMessage());
}
//最终通知:相当于finally代码块中的内容,有没有异常都执行
public void after(){
System.out.println("最终通知============");
}
}
步骤三:在applicationContexl04.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="productDao" class="com.zjw.spring.spring02.impl.ProductDaoImpl"></bean>
<!--将切面类交给SPRING管理-->
<bean id="myAspect" class="com.zjw.spring.spring02.Proxy.MyAspectXML"/>
<!--通过AOP的配置完成对目标类产生代理-->
<aop:config>
<!--表达式配置那些类的哪些方法需要进行增强-->
<aop:pointcut id="pointcut1" expression="execution(* com.zjw.spring.spring02.impl.ProductDaoImpl.save(..))"/>
<aop:pointcut id="pointcut2" expression="execution(* com.zjw.spring.spring02.impl.ProductDaoImpl.delete(..))"/>
<aop:pointcut id="pointcut3" expression="execution(* com.zjw.spring.spring02.impl.ProductDaoImpl.update(..))"/>
<aop:pointcut id="pointcut4" expression="execution(* com.zjw.spring.spring02.impl.ProductDaoImpl.find(..))"/>
<!--配置切面-->
<aop:aspect ref="myAspect">
<!--前置通知-->
<aop:before method="checkPri" pointcut-ref="pointcut1"/>
<!--后置通知-->
<aop:after-returning method="writeLog" pointcut-ref="pointcut2" returning="result"/>
<!--环绕通知,可以接受到目标函数update的返回值,而且与不用像后置通知那样,在后面添加returning的配置-->
<aop:around method="around" pointcut-ref="pointcut3"/>
<!--异常抛出通知-->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="ex"/>
<!--最终通知-->
<aop:after method="after" pointcut-ref="pointcut4"/>
</aop:aspect>
</aop:config>
</beans>
步骤四:编写测试类,下图是Spring单元测试需要引入的包
package com.zjw.spring.spring02.test;
import com.zjw.spring.spring02.ProductDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
//下面这两个注解之前没解释,是Spring的单元测试注解,第一个参数固定,第二个直接连接到了applicationContexl04.xml文件
//这两个注解的使用需要引入一个jar包,图片见下
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext04.xml")
public class SpringTest {
@Resource(name ="productDao")
private ProductDao productDao;
@Test
public void demo01(){
productDao.save();
productDao.update();
productDao.find();
productDao.delete();
}
}
- 切入点表达式
在上面步骤三的配置文件中有一个表达式
execution(表达式)
表达式:
[方法访问修饰符] 方法返回值(一般用*号通配符) 包名.类名.方法名(方法的参数,一般是…)
说明:当然上面的包名或者类名或者方法名都可以用星号表示,表示增强一个包,一个类,或者一个范围中的所有方法,下图中最后一句里面dao后面有两个‘.’,表示dao包下的所有子包。
五、Spring的基于AspectJ的注解的AOP开发
步骤一:编写目标类
package com.zjw.spring.spring03.Dao;
public class OrderDao {
public void save(){
System.out.println("保存订单。。。。。");
}
public String update(){
System.out.println("修改订单。。。。。");
return "林冲";
}
public String delete(){
System.out.println("删除订单。。。。。");
return "诸葛亮";
}
public void find(){
System.out.println("查找订单。。。。。");
// int i = 1/0;
}
}
步骤二:编写切面类MyAspectAnno,可以看到切面类中为了方便修改,用函数pointcut代替了表达式的书写,当多个目标函数被一个函数增强时,只需要改变切入点就行了。还要注意标识切面类的注解@Aspect,还要注意各种通知对应的注解。
package com.zjw.spring.spring03.Aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
//注解对的切面类
@Aspect
public class MyAspectAnno {
@Before(value = "MyAspectAnno.pointcut1()")
public void before(){
System.out.println("前置增强=============");
}
//后置通知
@AfterReturning(value = "MyAspectAnno.pointcut4()",returning = "result")
public void afterReturning(Object result){
System.out.println("后置增强=============="+result);
}
//环绕通知
@Around(value = "MyAspectAnno.pointcut2()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前通知==============");
Object obj = joinPoint.proceed();
System.out.println("环绕后通知=================" + obj);
return obj;
}
//异常抛出通知
@AfterThrowing(value = "MyAspectAnno.pointcut3()",throwing = "e")
public void afterThrowing(Throwable e){
System.out.println("我是异常,我被抛出了==========="+e);
}
//最终通知,也就是当发生异常的时候,他仍然会显示,但是得和异常在一个函数里
@After(value = "MyAspectAnno.pointcut3()")
public void after(){
System.out.println("最终通知来了来=================");
}
//切入点注解
@Pointcut(value = "execution(* com.zjw.spring.spring03.Dao.OrderDao.save(..))")
private void pointcut1(){}
@Pointcut(value = "execution(* com.zjw.spring.spring03.Dao.OrderDao.update(..))")
private void pointcut2(){}
@Pointcut(value = "execution(* com.zjw.spring.spring03.Dao.OrderDao.find(..))")
private void pointcut3(){}
@Pointcut(value = "execution(* com.zjw.spring.spring03.Dao.OrderDao.delete(..))")
private void pointcut4(){}
}
步骤三:编写配置文件xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.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">
<!--在配置文件中开启注解的AOP的开发-->
<aop:aspectj-autoproxy/>
<!--配置目标类-->
<bean id="orderDao" class="com.zjw.spring.spring03.Dao.OrderDao"></bean>
<!--配置切面类-->
<bean id="myAspect" class="com.zjw.spring.spring03.Aspect.MyAspectAnno"></bean>
</beans>
步骤四:编写测试类
package com.zjw.spring.spring03.Test;
import com.zjw.spring.spring03.Dao.OrderDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext05.xml")
public class test {
@Resource(name="orderDao")
private OrderDao orderDao;
@Test
public void demo01(){
orderDao.delete();
orderDao.find();
orderDao.save();
orderDao.update();
}
}
六、Spring的JDBC的模板的使用
- 引入JAR包
- 创建数据库和表
create database spring4_day03;
use spring4_day03;
create table account(
id int primary key auto_increment,
name varchar(20),
money double
);
- 使用JDBC的模板,保存数据,此处使用的是Spring本身的连接池
package com.zjw.spring.spring03.JDBC;
import org.junit.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
public class JdbcDemo01 {
//jdbc模板使用
@Test
public void demo01(){
//创建连接池
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///spring4_day03");
dataSource.setUsername("root");
dataSource.setPassword("root");
//创建jdbc模板
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("insert into account values (null,?,?)","二贝",10000d);
}
}
- 将连接池和模板交给Spring管理
引入Spring的配置文件
<!--配置Spring的内置的连接池-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!--属性注入-->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///spring4_day03"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!--配置Spring的JDBC的模板-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
- 编写测试类
package com.zjw.spring.spring03.JDBC;
import org.junit.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
public class JdbcDemo01 {
//jdbc模板使用
@Test
public void demo01(){
//创建连接池
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///spring4_day03");
dataSource.setUsername("root");
dataSource.setPassword("root");
//创建jdbc模板
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("insert into account values (null,?,?)","二贝",10000d);
}
}
- 把Spring内置的连接池更换为外界的连接池
方式一:DBCP的使用
-
引入jar包
-
配置DBCP连接池
<!--DBCP连接池的配置-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///spring4_day03"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
方拾二:C3P0的使用
-
引入C3P0连接池的jar包
-
配置C3P0连接池
<!--C3P0连接池的配置-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///spring4_day03"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
</bean>
- 如果要修改数据库,那么配置文件的方式每次都要修改,很麻烦,不符合AOP思想,所以要抽取配置到属性文件
-
定义一个属性文件
-
在Spring的配置文件中引入属性文件
<!--引入属性文件-->
<!--第一种方式通过一个bean标签引入的(很少)-->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:src/com/zjw/spring/spring03/jdbc.properties"></property>
</bean>
<!--第二种方式通过context标签引入-->
<context:property-placeholder location="classpath:src/com/zjw/spring/spring03/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>
- 编写测试
- 使用JDBC的模板完成CRUD的操作
package com.zjw.spring.spring03.JDBC;
import com.zjw.spring.spring03.domain.Account;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext06.xml")
public class JdbcDemo02 {
//这个属性注入只能在spring的单元测试中使用,在其他正常类中都要加扫描或者是
// <context:annotation-config></context:annotation-config>
@Resource(name = "jdbcTemplate")
private JdbcTemplate jdbcTemplate;
@Test
public void demo01(){
// jdbcTemplate.update("insert into account values (null,?,?)","李逵",25624d);
// jdbcTemplate.update("insert into account values (null,?,?)","宋江",25d);
// jdbcTemplate.update("insert into account values (null,?,?)","行者武松",23421d);
jdbcTemplate.update("insert into account values (null,?,?)","小旋风柴进",221d);
}
@Test
public void demo02(){
jdbcTemplate.update("update account set name = ?,money = ? where id = ?","花和尚鲁智深",1d,1);
}
@Test
public void demo03(){
jdbcTemplate.update("DELETE FROM account WHERE id = ?",3);
}
@Test
public void demo04(){
String name = jdbcTemplate.queryForObject("select name from account where id = ?",String.class,5);
System.out.println(name);
}
@Test
public void demo05(){
Long count = jdbcTemplate.queryForObject("select count(*) from account",Long.class);
System.out.println(count);
}
@Test
public void demo06(){
Account account = jdbcTemplate.queryForObject("SELECT * from account where id = ?", new MyRowMapper(),6);
System.out.println(account);
}
@Test
public void demo07(){
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 resultSet, int i) throws SQLException {
Account account = new Account();
account.setId(resultSet.getInt("id"));
account.setName(resultSet.getString("name"));
account.setMoney(resultSet.getDouble("money"));
return account;
}
}
}
========================分割线==================================
package com.zjw.spring.spring03.domain;
public class Account {
private String name;
private Integer id;
private Double money;
public String getName() {return name; }
public void setName(String name) { this.name = name;}
public Integer getId() {return id; }
public void setId(Integer id) { this.id = id;}
public Double getMoney() { return money; }
public void setMoney(Double money) { this.money = money;}
@Override
public String toString() {
return "Account{" +
"name='" + name + '\'' +
", id=" + id +
", money=" + money +
'}';
}
}