Spring

本文详细介绍了Spring框架,包括其作为轻量级Java开发框架的角色,Spring的各版本,特别是IOC(控制反转)和AOP(面向切面编程)的概念。文章通过实例演示了Spring如何管理Bean,如使用XML配置和注解实现依赖注入,以及Spring的AOP实现,包括JDK动态代理和Cglib代理。此外,还讨论了Spring的JDBC模板在数据库操作中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、Spring的概述

  1. 什么是Spring
    Spring是一个开源框架,Spring是于2003年兴起的一个轻量级的java开发框架,简单来说,Spring是一个分层的java SE/EE一站式轻量级开源框架。
    一站式框架:有EE开发的每一层解决方案
    web层:SpringMVC
    Service层:Spring的Bean管理,Spring声明式事务
    Dao层:Spring的jdbc模板,Spring的ORM模板
  2. Spring的版本
    Spring3.X和Spring4.X

二、Spring的IOC

  1. Spring的入门(IOC)
    什么是IOC
    IOC:Inversion of Control(控制反转),将对象的创建权反转给Spring
    在这里插入图片描述
    Spring的开发包
    在这里插入图片描述
    解压后是如下目录
    在这里插入图片描述
    docs: Spring的开发规范和API
    libs: Spring的开发的jar和源码
    schema: Spring的配置文件的约束
  2. 创建web项目,引入jar包
    在这里插入图片描述
  3. 对于IOC的理解,我认为是在java中免去了实例化对象(new 类名)的步骤,把这一步转交给了一个xml配置文件(就是交给Spring),具体步骤如下。
  4. 创建一个接口UserDAO,并且创建类UserDAOImpl实现该接口。
    在这里插入图片描述

在这里插入图片描述

  1. 在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>
  1. 编写测试类,注意测试类中的getBean函数的参数userDAO,对应的是xml中的id,所以创建的是UserDAOImpl的对象。

在这里插入图片描述

  1. 现在是有类的实例化对象了,但是对象的属性能不能也写在配置文件中?
    这就需要引入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>

在这里插入图片描述

  1. Bean标签中有id和name的配置
    id:使用了约束中的唯一约束,里面不能出现特殊字符的。
    name:并非使用约束中的唯一约束。(理论上可以出现重复的,但是实际开发不能出现的)里面可以出现特殊字符。
  2. 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>

在这里插入图片描述
在这里插入图片描述

  1. Bean的作用范围的配置
    scope:Bean的作用范围
  • singleton:默认的,Spring会采用单例模式创建这个对象,在单例模式下,创建的对象都是同一个,无论是创建几个对象,其地址都是相同的。创建多个对象只会触发一次init-method函数。
  • prototype:多例模式,创建的多个对象其地址都不一样,而且每创建一次对象,都会触发init-method函数。
  • request:应用在web项目中,Spring创建这个类以后,将这个类存入到request范围中。
  • session:应用在web项目中,Spring创建这个类以后,将这个类存入到session范围内。
  • globalsession :应用在web项目中,必须在porlet环境下使用。但是如果没有这种环境,相对于session。
  1. 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>

在这里插入图片描述

  1. Spring的分模块开发的配置
    分模块配置,在加载配置文件的时候,在一个配置文件中引入多个配置文件

在这里插入图片描述

三、Spring的基于IOC的注解开发

  1. 注解开发
    就是承接上一部分的xml配置,使用注解代替xml文件把类交给Spring管理,在使用注解开发之前,需要在原来的jar包中再添加一个aop的包,

在这里插入图片描述

  1. 引入相关配置文件
    引入约束,在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>
  1. 编写相关的类
    编写UserDao接口和UserDaoImpl类。

在这里插入图片描述

在这里插入图片描述

  1. 配置注解扫描
    注解扫描,是让Spring知道在哪个类里面有注解。
<!--Spring的IOC的注解的入门    -->
    <!--使用IOC的注解开发,配置组件扫描-->
    <!--扫描是为了扫描类上的注解-->
    <context:component-scan base-package="com.zjw.spring.spring02"/>
  1. 在相关的类上添加注解
    在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中保存用户的方法执行了。。。");
    }
}

在这里插入图片描述在这里插入图片描述

  1. Spring的Bean管理中常用的注解
    @Component注解(作用在类上)
    在这里插入图片描述
    属性注入的注解:(使用注解注入的方式,可以不用提供 set 方法.)
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述

  2. Bean的生命周期和作用范围的注解
    @Scope:

  • singleton:单例
  • prototype:多例
    在这里插入图片描述
    @PostConstruct :相当于 init-method
    @PreDestroy :相当于 destroy-method
    在这里插入图片描述
  1. 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 的动态代理 :针对没有实现接口的类产生代理. 应用的是底层的字节码增强的技术 生成当前类
    的子类对象.
  1. 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();
    }
  1. 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();
    }
  1. 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开发搞的包。
    在这里插入图片描述
  1. 实现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();
    }
}

在这里插入图片描述

  1. 切入点表达式
    在上面步骤三的配置文件中有一个表达式
    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的模板的使用

  1. 引入JAR包
    在这里插入图片描述
  2. 创建数据库和表
create database spring4_day03;
use spring4_day03;
create table account(
	id int primary key auto_increment,
	name varchar(20),
	money double
);

  1. 使用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);
    }
}
  1. 将连接池和模板交给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>
  1. 编写测试类
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);
    }
}
  1. 把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>
  1. 如果要修改数据库,那么配置文件的方式每次都要修改,很麻烦,不符合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>
  • 编写测试

在这里插入图片描述

  1. 使用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 +
                '}';
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值