Spring框架小结

目录

1.Spring是什么?

2.搭建Spring(Hello World版本)

        2.1导入spring的核心jar包(给出坐标)

        2.2创建实体类(举例Admin)

        2.2编写spring配置文件+配置bean

                 2.3测试(创建Test类)

 3.控制反转IOC

 4.Spring对Bean的管理

        4.1xml配置方式对Bean管理

        4.2xml配置方式的依赖注入(DI)

               4.2.1set方法注入

               4.2.2构造方法注入

        4.3利用注解方式对Bean管理

               4.3.1开启注解配置扫描

               4.3.2注解标签讲解(7种)

        4.4xml配置与注解方式的区别

5.Spring管理数据源+JdbcTemplate

        5.1导入jar包(jdbc+阿里数据源+mysql驱动)

        5.2 配置数据源和JdbcTemplate信息

        5.3使用举例(非重点)

 6.Aop(面向切面编程)

        6.1AOP概述

        6.2AOP的基本概念

        6.3SpringAOP的实现

                6.3.1下载Aop-jar包

                6.3.2测试环境搭建

                6.3.2xml方式实现动态代理

                6.3.3注解方式实现动态代理

7.spring事务管理(使用了Aop思想)

         7.1在db.xml文件中配置事务管理类,并注入数据源

         7.2在spring.xml文件中开启注解事务管理

         7.3Service层中添加事务

         7.4六种情况下@Transactional不生效(重点)

8.spring事务传播行为


1.Spring是什么?

        Spring 是一款轻量级的,IOC 和 AOP 的Java 开发框架,它是为了简化企业级应用开发而生的。 

        轻量级的:Spring框架的核心功能jar包并不大,3M左右,运行时占用内存小,运行效率高。  

2.搭建Spring(Hello World版本)

        2.1导入spring的核心jar包(给出坐标)

<!-- spring-context -->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.2.2.RELEASE</version>
</dependency>

        2.2创建实体类(举例Admin)

public class Admin {

    private int id;

    private String account;

    private String password;

    public Admin() {
        System.out.println("Admin无参构造方法");
    }

    public Admin(int id, String account, String password) {
        System.out.println("Admin带参构造方法");
        this.id = id;
        this.account = account;
        this.password = password;
    }

    public int getId() {
        System.out.println("调用了get");
        return id;
    }

    public void setId(int id) {
        System.out.println("调用了set");
        this.id = id;
    }

    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "Admin{" +
                "id=" + id +
                ", account='" + account + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

        2.2编写spring配置文件+配置bean

在resources目录下创建spring.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
        https://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">

    <bean id="admin" class="com.ffyc.ssm.model.Admin</bean>

</beans>

        2.3测试(创建Test类)

public class Test01 {
    public static void main(String[] args) {
        //读取配置文件,ClassPathXmlApplicationContext就是spring中的实现者
        ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("spring.xml");
        //Object admin = app.getBean("admin"); 它也不知道返回的是啥类型,只是根据传来的键去找值对象,返回即可
        Admin admin = app.getBean("admin", Admin.class);//指定类型返回
        System.out.println(admin);
    }
}

            输出结果:

Admin无参构造方法
Admin{id=0, account=null, password=null}

 3.控制反转IOC

        IOC:可理解为控制反转,一种设计思想,以前我们获取对象都是我们自己new对象,自己实现(及正控),IOC的思想(反控)就是我们把创建对象的控制权交给spring框架,让框架去帮助我们创建管理对象,如果我们需要直接在在IOC容器当中获取即可。

IOC容器里面存储的格式可理解为:Map("id/类型/name",所创建的对象)

底层实现方式: 解析 xml/扫描注解标签 + 工厂模式 + 反射机制 

 4.Spring对Bean的管理

        4.1xml配置方式对Bean管理

语句含义
<bean>配置需要spring框架管理的类
id唯一的标识,可利用id来获取spring框架创建的代理对象
class所管理类的地址,地址要写全
name与id作用基本一致,也可通过name来获取对象
<alias>起别名,例如:<alias name="admin2"   alias="admin3,admin4"></alias>
scopesingleton(默认值)在 Spring 中只存在一个 bean 实例, 单例模式,读取spring.xml配置文件时创建。
prototype:原型的,getBean()的时候都会 new Bean(),获取对象时创建,可创建多个。

        4.2xml配置方式的依赖注入(DI)

        在spring创建对象时可以给对象依赖的属性赋值,我们称之为依赖注入。

                4.2.1set方法注入

<bean id="admin"  class="com.ffyc.ssm.model.Admin" scope="prototype">
    <property name="id" value="1"></property>
    <property name="account" value="zhangsan"></property>
    <property name="password" value="123"></property>-->
</bean>

 测试结果:

        Admin无参构造方法
        调用了set
        Admin{id=1, account='zhangsan', password='123'}

               4.2.2构造方法注入

<bean id="admin" class="com.ffyc.ssm.model.Admin" scope="prototype">
    <constructor-arg name="id" value="2"></constructor-arg>
    <constructor-arg name="account" value="lisi"></constructor-arg>
    <constructor-arg name="password" value="456"></constructor-arg>
</bean>

测试结果:

        Admin带参构造方法
        Admin{id=2, account='lisi', password='456'} 

        4.3利用注解方式对Bean管理

                4.3.1开启注解配置扫描

        在spring.xml配置文件中开启注解配置 ,运行时,会扫描所配置的包里面,然后将带有注解的类并且scope必须为"singleton"的进行创建。

 <context:component-scan base-package="com.ffyc.ssm"> </context:component-scan>

                4.3.2注解标签讲解(7种)

作用在类上的注解标签                作用
@Component(value=" ") 

一般作用在model

@Service(value=" ")一般作用在service层
@Repository(value=" ")一般作用在dao层
@Scope(value="prototype/singleton")原型/单例

        以上前三种注解都可以实现创建对象功能,只是为了后续扩展功能,在不同的层使用不同的注解标记 。

作用在属性上(依赖注入)                                                 功能及作用
@Autowired(spring提供)

byType(默认使用) 自动注入,该注解默认使用按类型自动装配Bean的方式

例如:

@Autowired

AdminDao  adminDao; 

byName,结合@Qualifier注解,value 属性用于指定要匹配的 Bean 的 id 值。

例如:

@Autowired

@Qualifier(value = "adminDao")

AdminDao  adminDao; 

@Resources(JDK提供)

byType(默认使用) 利用属性类型去检索

例如:

@Resource

AdminDao adminDao;

byName,其name属性用于指定要匹配的 Bean 的 id 值。

@Resource(name="adminDao")

AdminDao adminDao;

        注意:Autowired(required=true) 默认情况下它要求依赖对象必须存在,不允许为null,如果要使可以允许为null值,可以设置它的required属性为false。

        4.4xml配置与注解方式的区别

xml:

优点:配置和代码分离,修改后,只需要重启服务器即可。

缺点:编写麻烦,效率低。 

注解方式:

优点:代码少,直观简洁。

缺点:以硬编码的方式写入java代码中,修改需要重新编译项目。 

5.Spring管理数据源+JdbcTemplate

        Spring是一站式框架,spring自身也提供了持久层的JdbcTemplate。我们在resources目录下创建db.xml,里面写关于jdbc的一些配置信息,以及创建congig.properties配置文件,里面配置数据库连接的一些信息,以后方便修改。

        5.1导入jar包(jdbc+阿里数据源+mysql驱动)

<!-- spring-jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>

<!-- 阿里数据源 -->
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.1.10</version>
</dependency>

<!--mysql驱动-->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>8.0.16</version>
</dependency>

        5.2 配置数据源和JdbcTemplate信息

        config.properties:

        db.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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!--jdbc配置文件-->

    <!--加载config.properties文件-->
    <context:property-placeholder location="classpath:config.properties"></context:property-placeholder>

    <!--spring统一管理数据库连接对象-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${driver}"></property>
        <property name="url" value="${url}"></property>
        <property name="username" value="${uname}"></property>
        <property name="password" value="${pwd}"></property>
        <property name="initialSize" value="5"></property>
        <property name="maxActive" value="10"></property>
    </bean>

    <!--创建spring框架封装的jdbc实现类,以后引入mybatis框架,也是只需要注入数据源对象,不用jdbcTemplate
        而且jdbcTemplate的事务采用的是以前jdbc的执行一条sql自动提交。
    -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入数据源对象-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
</beans>

        spring.xml:

 <!--将配置jdbc的配置文件导入进来-->

<import resource="classpath:db.xml"></import>

         5.3使用举例(非重点)

        配置好以上相关信息后,就可以使用JdbcTemplate了,因为我们最终的话要集成mybatis框架,所以JdbcTemplate并不是重点。

         以下只是将JdbcTemplate的一些用法语句展示一下————

@Repository(value = "adminDao") 暂时注释
public class AdminDao1 {

    @Autowired
    @Qualifier(value = "jdbcTemplate") 
    JdbcTemplate jdbcTemplate; //依赖注入

    public  void save(Admin admin){
        jdbcTemplate.update("insert into admin(account,password) value(?,?)","wangwu","789");
        jdbcTemplate.update("delete from admin where id = ?",5);
        Admin admin1 = jdbcTemplate.queryForObject("select *  from admin where id =?", new RowMapper<Admin>() {
            @Override
            public Admin mapRow(ResultSet resultSet, int i) throws SQLException {
                Admin admin1 = new Admin();
                admin1.setId(resultSet.getInt("id"));
                admin1.setAccount(resultSet.getString("account"));
                admin1.setPassword(resultSet.getString("password"));
                return admin1;
            }
        }, 1);
        System.out.println(admin1);

        List<Admin> list = jdbcTemplate.query("select * from admin", new RowMapper<Admin>() {
            @Override
            public Admin mapRow(ResultSet resultSet, int i) throws SQLException {
                Admin admin1 = new Admin();
                admin1.setId(resultSet.getInt("id"));
                admin1.setAccount(resultSet.getString("account"));
                admin1.setPassword(resultSet.getString("password"));
                return admin1;
            }
        });
        System.out.println(list);
    }
}

 6.Aop(面向切面编程)

        6.1AOP概述

        AOP:全称Aspect Oriented Programming,意为:面向切面编程,AOP是OOP思想的延续(一种补充),它是一种编程技巧,并不是spring框架所特有的,而是spring框架使用了这种思想,aop思想是我们可以把代码分为业务代码和非业务代码(比如 打印日志、提交事务、统一验证),之后可以把非业务代码抽取到一个类当中,在业务代码中不需要展现,而在执行业务代码前后或出现异常时,利用切面的思想,通过spring框架创建的特有代理对象来调用非业务代码,这样的话,减少重复,注重业务,即降低了代码的耦合度,又提高了程序的可重用性,就大大提高了开发效率。

        代理模式更关注于为单个对象提供代理和扩展功能,而AOP则更侧重于在整个应用程序中横切关注点的模块化和管理。

        6.2AOP的基本概念

连接点(JoinPoint)类中可以被增强的方法,我们称之为连接点
切入点(PointCut)实际被增强的方法,我们称之为切入点
通知(Advice)抽取出来的非业务代码的功能,指要做的事情,称之为通知
目标(Target)增强的方法所处的类,称为目标类
切面(Aspect)把通知添加到切入点的整个过程我们称为切面
代理(Proxy)调用通知的代理对象,由spirng框架创建

通知分为5种:

* 前置通知——before 业务执行前执行

* 后置通知——after-returning 业务方法执行后执行,当出现异常不执行

* 异常通知——after-throwing 业务出现异常时调用

* 最终通知——after 业务方法执行后执行,当出现异常也会执行

* 环绕通知——包含概括了前四种通知

        6.3SpringAOP的实现

                6.3.1下载Aop-jar包

<!--aop jar包-->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aspects</artifactId>
  <version>5.2.2.RELEASE</version>
</dependency>

                6.3.2测试环境搭建

        为了测试我们Aop是否成功实现,我们搭建一个案例,通过service层调用dao层的save()方法来实现新增管理员。

Test类:

public class Test {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("spring.xml");
        AdminService adminService = app.getBean("adminService", AdminService.class);
        adminService.save();
    }
}

AdminService类:

@Service(value = "adminService")
public class AdminService{

    @Autowired
    @Qualifier(value = "adminDao")
    AdminDao adminDao; //依赖注入

    public void save(){
        adminDao.save();
    }

}

AdminDao类:

@Repository(value = "adminDao")
public class AdminDao {
    @Autowired
    @Qualifier(value = "jdbcTemplate")
    JdbcTemplate jdbcTemplate; //依赖注入

    public void save(Admin admin){
        jdbcTemplate.update("insert into admin(account,password) value(?,?)","wangwu","789");
        int i = 10/0;
        System.out.println("保存成功");
    }
}

        非业务代码(通知类): 

public class MyUtil {
    public  void printLog(){
        System.out.println("打印日志");
    }
    public void commit() {
        System.out.println("提交事务");
    }

    public void throwable(Throwable e){
        System.out.println("异常:"+e.getMessage());
    }

    /*环绕通知   ProceedingJoinPoint 连接点指向的是切入点方法*/
    public void around(ProceedingJoinPoint joinPoint){
        printLog();//前置通知
        try {
            joinPoint.proceed();  //调用自己的业务代码
            System.out.println("后置通知");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("异常通知:"+throwable.getMessage());
        }finally {
            commit();  //最终通知
        }
    }
}

                6.3.2xml方式实现动态代理

为了方便起见,我们在resources目录下创建aopdemo.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
                            https://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/aop
                            http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--
        把非业务代码(通知交给spring框架来管理)
    -->
    <bean id="myutil" class="com.ffyc.ssm.util.MyUtil"></bean>

    <aop:config>
        <!-- 配置切入点 -->
        <aop:pointcut id="saveAdmin" expression="execution(* com.ffyc.ssm.dao.AdminDao.save(..))"/>

        <!--将通知与切入点配置,生成的代理对象就知道该怎么调用-->
        <aop:aspect ref="myutil">
            <!--如果在xml中配置环绕通知,在执行切入点方法前,会先执行抽取的around方法,在around里再调用执行切入点方法-->
            <aop:around method="around" pointcut-ref="saveAdmin"></aop:around>
        </aop:aspect>
    </aop:config>

</beans>

        将此xml导入到spring.xml配置文件当中:

<!--将配置aop的xml文件导入,利用xml方式配置Aop-->

<import resource="classpath:aopdemo.xml"></import>

        运行Test,测试结果:

打印日志

//异常信息

异常通知:/ by zero

提交事务

        但是我们会发现,即使save()方法中我们出现异常,但是所添加的数据在数据库中仍然会添加,所以spring中JdbcTemplate的事务采用的和之前JDBC的一样,执行完一条sql后直接自动提交。

            6.3.3注解方式实现动态代理

注释刚才的导入的aopdemo.xml,在spring.xml文件中启动AspectJ支持:

<!--启动AspectJ支持(自动代理) 注解方式配置Aop-->

<aop:aspectj-autoproxy />

        在Myutil中做配置:

//基于注解方式配置Aop  所抽取的通知类
@Component  //让spring管理生成对象,让spring框架检索到
@Aspect     //表明装有通知的类 /切面,就可以在方法上使用通知注解了
public class Myutil1 {

    //前置通知
    //@Before("execution(* com.ffyc.ssm.dao.AdminDao.save(..))")
    public  void printLog(){
        System.out.println("打印日志");
    }

    //后置通知
    //@AfterReturning("execution(* com.ffyc.ssm.dao.AdminDao.save(..))")
    public void commit() {
        System.out.println("提交事务");
    }

    //异常通知
    //@AfterThrowing(value = "execution(* com.ffyc.ssm.dao.AdminDao.save(..))",throwing = "e")
    public void throwable(Throwable e){
        System.out.println("异常:"+e.getMessage());
    }

    //环绕通知
    @Around("execution(* com.ffyc.ssm.dao.AdminDao.save(..))")
    public void around(ProceedingJoinPoint joinPoint){
        System.out.println("前置通知");
        try {
            joinPoint.proceed();  //调用自己的业务代码
            System.out.println("后置通知");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("异常通知:"+throwable.getMessage());
        }finally {
            System.out.println("最终通知");
        }
    }
}

         运行Test,测试结果:

前置通知

//异常信息
异常通知:/ by zero
最终通知 

        和xml配置方式所达到的效果一致,但是注解方式更加的方便、简洁。

        注意:用来调用通知的代理对象并不是spring创建的Myutil对象,而是spring框架中自己创建的特有代理对象,让spring管理创建Myutil,是因为需要让spring框架检索到这个通知类。

7.spring事务管理(使用了Aop思想)

         事务:事务是数据库为了保障数据一致性的功能,把对数据库的多条操作,可以看作为一个执行单元,这个单元可称为事务。事务的基本特征就是原子性,要么多条sql同时执行成功,要么一条都不执行。spring框架把提交事务和管理事务的功能都封装好了,底层使用了Aop的思想,代理我们来对事务进行管理。

        spring中事务管理分为两种形式,一种是编程式事务,还有一种是声明式事务。编程式事务很少用到,要自己写代码实现,声明式事务建立在AOP基础上,是方法级别的,分为基于xml配置和注解方式实现,这里我们采用的是注解方式实现。

         7.1在db.xml文件中配置事务管理类,并注入数据源

<!-- 配置spring事务管理类, 并注入数据源 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

    <property name="dataSource" ref="dataSource"></property>
</bean>

         7.2在spring.xml文件中开启注解事务管理

<!-- 开启注解事务管理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>

         7.3Service层中添加事务

        对于经典案例转账,对于service层来讲,转账是一个单元操作,所以得把事务管理的注解标签加在service层上 ,不要加在dao层里,因为集成了mybatis之后,dao里一个方法对应一条sql,不能把事务管理加到多条dao方法上,起不到原子性的作用 。 一个业务逻辑中,可能要执行dao中的多条sql操作,所以得把多个sql放在同一个事务下管理。

@Transactional 添加到类上表示类中的所有方法都会添加事务管理功能

@Transactional 只添加到某个方法,表示此方法在事务管理中进行

         7.4六种情况下@Transactional不生效(重点)

1.@Transactional所修饰的方法访问权限不是public
2.修饰的方法出现的异常被catch所捕获

3.方法出现运行时异常事务生效,如果出现编译器异常,事务不生效,所以可设置为————

                        @Transactional(rollbackFor = Exception.class)

4.事务传播行为设置错误
5.数据库引擎不支持,innodb支持事务(多用于增,删,改操作的表),myisam不支持事务(多用于查询操作的表)

6.在同一个类当中使用spring非代理对象调用事务方法,方法不生效。

           在同一个类当中,如果此方法没有被事务管理,然后在此方法内还调用了事务管理的方法,就例如: zhuanzhang() == this.zhuanzhang(),  this相当于又自己new对象来调用,这样的话调用的事务方法就不被事务管理了。 必须用spring所管理创建的对象(不是new创建的代理对象)来调用事务方法!!!

8.spring事务传播行为(代理机制+AOP)

        事务传播行为是spring框架独有的事务增强特性,不属于事务提供方数据库的行为。

事务传播行为主要研究的地方在methodA方法中调用methodB方法,那么methodB方法是整合于methodA中的事务一起被管理,还是methodB独自又新建一个事务,它们之间独立运行,互不干涉。这就是又methodB的事务传播行为来决定的!

         spring中定义了7种事务传播行为,这里我们举例三种:

propagation = Propagation.REQUIRED

如果A有事务,那么B就整合在A事务中,一起被管理(合并)。

如果A不存在事务,B存在事务,那么B就在自己的事务中运行,于A无关,各干各的。

propagation = Propagation.REQUIRES_NEW

如果A有事务,那么B就自己单开一个事务独自运行(挂起),于A无关,各干各的。

如果A不存在事务,B会自己新建属于自己的事务,独立运行。

 propagation = Propagation.NEVER

如果可以执行以非事务方式执行。

如果A存在事务,调用B,会抛出异常。

spring框架是一站式框架在于它对持久层和web层进行了封装,并且可以很好的管理其他框架。 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值