spring详解

今天我们来学习一个新的框架spring!!!

spring是什么呢?

spring是2003年兴起的,是一款轻量级、非侵入式的IOC和AOP的一站式的java开发框架,为简化企业即开发而生。

轻量级:spring核心功能的jar包不大

非侵入式:我们的业务代码不需要继承或实现spring中的任何类和接口

IOC:控制反转,以前项目都是在哪儿用到对象,在哪儿new,把生成对象的权利反转给spring框架

Aop:面向切面编程

一站式框架:

  • 提供核心功能,主要是IOC,创建管理对象
  • 提供面向切面编程,增强程序扩展
  • 对数据访问层进行了封装(重点在事务管理)
  • 对Web层进行封装,使得请求更加的便捷

Spring思想是什么?由框架统一对项目的类进行管理(创建对象,后期增强一些功能),在需要的地方注入即可。

 Core Container(核心容器):

  • Beans: 管理 Beans
  • Core: Spring 核心
  • Context: 配置文件

 IOC(控制反转):就是将原本在程序中手动创建对象的控制权,交由 Spring 框架来
管理。

在Spring Bean对象管理

  • 基于xml配置管理

   <bean id="adminservice" class="com.ffyc.ssm.service.AdminService">
        <property name="adminDao" ref="adminDao"></property><!--注入-->
    </bean>
让spring帮我们管理项目中的类
方式1:在xml中进行配置
     配置需要让spring进行管理的类

     id="唯一的标识"
     class="让spring管理的类名"

     bean?
       由spring框架创建并管理的对象称为一个bean对象

     Scope="singleton 默认值"  单例的  在整个应用程序中只创建一个对象,在spring框架启动时就创建好了
            prototype   原型的  每次获取时创建一个对象,可以创建多个

      spring框架创建对象时,需要为对象的属性进行赋值操作:  这个赋值操作称为依赖注入
         1.属性赋值  getXXX,setXXX方法
         2.构造方法赋值
  •  注解方式实现
  1.  注解开发准备工作
  2. 注解需要的 jar 包
  3. 注解功能封装在 AOP 包中,导入 Spring aop jar 包即可
  4. 开启注解扫描
    <context:component-scan base-package="包名"> </context:component-scan>

     5. 注解创建对象

@Component(value=“user”)等于
<bean id=“user” class=“”></bean>
@Service
@Repository
以上注解都可以实现创建对象功能,只是为了后续扩展功能,在不同的层
使用不同的注解标记
@Scope(value=“prototype”)
原型
@Scope(value=“ singleton ”)
单例

注解方式注入属性

/*
     * Map("adminDao,AdminDao",对象)
     * @Autowired
     * spring框架中提供的一个自动注入注解标签
     * 有两种方式去查找对象:
     * 1.byType 去spring容器中根据当前类型进行搜索
     * 2.byName 通过名称查找 需要结合当前@Qualifier(value="adminDao")
     *  @Autowired(required=true) 注入时,对象值不能为空,为空的话会进行报错
     *
     *@Resource
     * 是jdk中提供的一个注解标签
     * 有两种方式去查找对象:
     * 1.byType 去spring容器中根据当前类型进行搜索
     * 2.byName 通过名称查找  @Resource(name="adminDao")
     * */
//     @Autowired
//     @Qualifier(value="adminDao")

 注解与XML的对比

  • 注解优点: 方便,直观,高效(代码少,没有配置文件的书写那么复杂)。
  • 注解缺点:以硬编码的方式写入到 Java 代码中,修改是需要重新编译代码的。
  • xml 优点是: 配置和代码是分离的,在 xml 中做修改,无需编译代码,只需重启服务器即可将新的配置加载。
  • xml 的缺点是:编写麻烦,效率低,大型项目过于复杂。

 Spring JDBC

Spring 是一个一站式框架:Spring自身也提供了控制层的SpringMVC和持久层的Spring JdbcTemplate.

1.下载Spring JdbcTemplate的包

<!-- 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>

2.创建一个config.properties文件

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/数据库名?serverTimezone=Asia/Shanghai
uname=root//数据库账号
pwd=root//数据库密码

3.在spring配置文件中导入

<context:property-placeholder location="config.properties"/>

4.在db.xml中管理数据源对象

<!--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>

5.在db.xml中创建  JdbcTemplate

   <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

6.在Dao层获得 JdbcTemplate对象

 

 execute:无返回值,可执行 ddl,增删改语句
update:执行新增、修改、删除语句;
queryForXXX:执行查询相关语句;

AOP开发思想:开发好一个版本后,后期需要添加新的功能,就需要改变原来的代码,加入调用新功能的代码,开发麻烦,会存在大量的冗余的代码

AOP是一种编程技巧,不是代替OOP,可以使业务逻辑和非业务逻辑进行隔离,使得各个部分之间的耦合度降低,提高程序的复用性,提高了开发效率

AOP

Aop:将程序中的一些非业务逻辑代码进行提取,在不需要修改原来代码情况,为程序添加额外的功能,非业务逻辑代码(验证权限 打印日志 提交事务 统一异常处理)

实现的方法:是通过一个代理对象,告诉代理对象,调用哪个方法时,让代理对象去帮助我们代用哪个方法(AdminDao->生成一个代理对象)底层:动态代理模式

AOP并不是Spring框架中特有的,只是Spring框架引入这一思想

Aop的基本概念:

  • 连接点:类中可以被增强的方法,称为连接点
  • 切入点:类中实际被增强的方法,称为切入点(横切面切入的方法)
  • 通知:提取得非业务的功能称为通知
  • 切面:把通知添加到切入点的过程
  • 目标:代理的目标对象
  • 代理:向目标对象应用通知创建的代理对象

AspectJ 是一个基于 Java 语言的 AOP 框架,它提供了强大的 AOP 功能,且其实
现方式更为简捷,使用更为方便, 而且还支持注解式开发。配置步骤如下:

1.下载相关的Jar包

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

2.基于aspectj的xml配置方式实现

<bean id="aopdemo" class="com.ff.spring.aop.AopDemo"></bean>
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(*
com.ff.spring.service.UserService.adduser(..))" id="adduser"/>
<aop:pointcut expression="execution(*
com.ff.spring.service.UserService.*(..))" id="allmethod"/>
<!-- 配置通知和切入点 -->
<aop:aspect ref="aopdemo">
<aop:before method="savelog" pointcut-ref="adduser"/>
<aop:after method="savelog" pointcut-ref="adduser"/>
<aop:around method="aroundAdvice" pointcut-ref="adduser"/>
<aop:after-throwing method="exceptionAdvice" pointcut-ref="allmethod"
throwing="e" />
</aop:aspect>
</aop:config>

该通知有五种:

  1. 前置通知:方法执行前调用
  2. 后置调用:业务方法执行后调用,当方法出现异常后不执行
  3. 异常通知:业务方法出现异常时调用
  4. 最终通知:业务方法执行后调用,当方法出现异常时也会调用
  5. 环绕通知
 <aop:config>
       <!--配置切入点-->
        <aop:pointcut id="saveAdmin" expression="execution(* com.ffyc.ssm.dao.AdminDao.saveAdmin(..))"/>
       <!--将通知与切入点进行配置,生成的代理对象就知道如何调用-->
        <aop:aspect ref="myutil">
<!--               <aop:before method="printLog" pointcut-ref="saveAdmin"></aop:before>-->
<!--               <aop:after-returning method="printLog" pointcut-ref="saveAdmin"></aop:after-returning>-->
<!--               <aop:after method="printLog" pointcut-ref="saveAdmin"></aop:after>-->
<!--               <aop:after-throwing method="exceptionAdvice" pointcut-ref="saveAdmin" throwing="e"></aop:after-throwing>-->
            <aop:around method="aroundAdvice" pointcut-ref="saveAdmin"></aop:around>
        </aop:aspect>
   </aop:config>

基于注解方式实现

@Component//让spring管理生成对象
@Aspect//启动Aspect 开启自动代理  表面装有通知的类/切面
public class MyUtil {
//    @Before("execution(* com.ffyc.ssm.dao.AdminDao.saveAdmin(..))")
//     public void printLog(){
//         System.out.println("打印日志");
//     }
//
//     public void commit(){
//        System.out.println("事务提交");
//     }
//    @AfterThrowing(value="execution(* com.ffyc.ssm.dao.AdminDao.saveAdmin(..))",throwing = "e")
//    public void exceptionAdvice(Throwable e){
//        System.out.println("异常通知"+e.getMessage());
//    }
//@Around("execution(* com.ffyc.ssm.dao.AdminDao.saveAdmin(..))")
    public void aroundAdvice(ProceedingJoinPoint point){
        try {
            System.out.println("前置通知");
            point.proceed();
            System.out.println("后置通知");
        } catch (Throwable throwable) {
//            throwable.printStackTrace();
//            System.out.println("异常通知");
        }
        System.out.println("最终通知");
    }
}

Spring事务管理

什么是数据库事务?

spring框架里面提供了事务管理的功能,事务管理是数据库提供佛仍一种功能,为了保证了数据在过程在过程中的准确性,事务管理是管理一组中有多个执行单元,一个事务就是一个单元,一个单元可以包含很多个SQL语句。

关系型数据库的基本特征:

  • 原子性特征(一次操作中的多条SQL语句,要么都执行,要么都不执行)
  • 隔离性
  • 持久性
  • 一致性

 Spring中事务管理有两种:

1.编程式事务管理-->在代码中自己写

2.声明式事务管理-->使用注解标签实现(底层思想是AOP思想,是方法级别的,在执行某个方法中,为方法添加额外的事务管理功能)

@Transactional标签的用法:
  1. 一般把@Transactional标签添加在service中
  2. @Transactional可以添加在service层中类上,类中的所有方法都会添加事务
  3. @Transactional如果值添加到方法上,表示此方法在事务管理进行

以下6种情况@Transactional不会生效:

  1. @Transactional应用在非public修饰的方法上(底层针对public修饰的方法)
  2. 方法中异常被catch捕获处理
  3. 编译器异常(事务不生效,默认情况下只对运行期异常进行捕获   rollbackFor=Expection.class 任何异常都能捕获)
  4. @Transactional事务传播行为设置错误
  5. 数据库引擎不支持事务(数据库引擎是mysql底层具体的一种数据处理实现的机制  常用的两个引擎  innodb(支持事务)  myisam(不支持事务))
  6. 同一个类中,使用非代理对象调用增强方法,用this调方法表示自己没有被进行任何加强

spring事务传播行为:

       事务传播行为(propagation behavior)(必须要有两个对象)指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。事务传播行为是 Spring 框架独有
的事务增强特性,他不属于的事务实际提供方数据库行为.

例如:A方法中调用另一个方法,B方法事务该如何进行?B事务是一个独立是我事务呢?还是B事务合并到A事务中呢?

以下是事务传播行为的7种方法 

下来我们简单的介绍3种比较常用的事务传播方式

1. PROPAGATION_REQUIRED

       指定的方法必须在事务内执行,若当前存在事务,加入到当前事务中,若当前没有事务,则创建一个新事务,这种传播行为是最常见的,也是 spring 默认的传播行为.

 2. PROPAGATION_SUPPORTS
      支持当前事务,如果当前没有事务,就以非事务方式执行。

 3. PROPAGATION_REQUIRES_NEW
     总是新建一个事务,如果当前存在事务,把当前事务挂起,直到新建的事务结束。

 BeanFactory和ApplicationContext

 在Spring中BeanFactory接口是IOC中最基础的接口,定义了最基本的方法

BeanFactory有非常多的实现类,每个实现类都有不同的职责(单一职责)功能DefaultListableBeanFactory是生产bean的工厂

 ApplicationContext也是间接继承了BeanFactory,BeanFactory相当于Spring的心脏,那么

 ApplicationContext就是完整的身躯(功能的实现),Spring容器是生成Bean实例的工厂,管理容器中的bean对象

区别:

1.BeanFactory不支持AOP、Web等插件,ApplicationContext不仅包含BeanFactory的所有功能,还支持spring各种插件

2.BeanFactory采用的是延迟加载形式来注入Bean的,只有调用getBean()时,才会对Bean进行加载实例化,这样我们就无法发现Spring配置上的问题,而ApplicationContext相反,在容器创建的启动的时候一次性创建了所有的Bean,我们就可以及时发现Spring中的配置错误,但是占用内存空间

Spring的生命周期

1.实例化

2.属性赋值

3.初始化

4.销毁

 Spring中的bean是线程安全的么?

Spring本身是不具备线程安全的特性,但是是否安全还是看scope中的Bean的情况

1.singleton:单例,默认作用域(存在着资源竞争)

2.prototype:原型,每次创建一个新对象(线程之间不存在Bean分享,没有线程安全问题)

3.request:请求,每次Http请求创建一个新对象

Bean的状态

有状态:有数据存储功能

无状态:不会保存数据

Bean循环依赖

 

@Component
public class A {
   @Autowired
    public B b;

    public A(){
        System.out.println("init B");
    }

}


@Component
public class B {
    @Autowired
    public A a;
    public B(){
        System.out.println("init A");
    }
}

在非spring环境中,循环依赖不是一个问题,但是在Spring中循环依赖就成了一个问题

 在Spring管理的bean时,在自动注入时,如果两个类相互之间关联,那么会出现注入时,另一个对象还没有完成初始化。

循环依赖解决方法:用过三级缓存(3个Map对象)

一级缓存(singletonObjects):主要存储初始化完成的对象

二级缓存(earlySingletonObjects):存储实例化完成的半成品bean对象,提前暴露给需要的地方

三级缓存(singletonFactories):放的是创建对象的工厂

 private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
 private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);

 代码如下:

 protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);//从一级缓存去获取bean
        if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                synchronized(this.singletonObjects) {
                    singletonObject = this.singletonObjects.get(beanName);//从二级缓存中查找,有没有提前暴露的半成品对象
                    if (singletonObject == null) {
                        singletonObject = this.earlySingletonObjects.get(beanName);
                        if (singletonObject == null) {
                            ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);//从三级缓存中取出对象的工厂对象
                            if (singletonFactory != null) {
                                singletonObject = singletonFactory.getObject();//通过工厂对象创建出单例对象
                                this.earlySingletonObjects.put(beanName, singletonObject);//把对象放入二级缓存
                                this.singletonFactories.remove(beanName);//删除创建对象的工厂
                            }
                        }
                    }
                }
            }
        }

        return singletonObject;
    }

循环依赖的根本就是实例化和初始化是分开处理的

Servlet的过滤器与Spring拦截器区别

       过滤器属于javaweb(servlet规范)中定义的,实现控制由服务器调度拦截范围更大,所有进入到web后端的请求,都可以被过滤器拦截。

Spring常用注解

bean的注解:

@Component : 泛指各种组件

@Controller、@Service、@Repository 都可以称为@Component

@Controller  : 控制层

@Service : 业务层

@Repository : 数据层访问层

Bean的生命周期:

@Scope :

    singleton:单例,一个spring容器中只有一个bean实例,默认模式

    prototype:每次创建一个bean对象

    request:web 项目中,给一个http request新建一个bean

    session : web项目中,给每一个会话新建一个bean对象

    globalSession : 给每一个globalSession新建一个bean对象

注入bean对象的注解:

@Autowired : spring提供

@Qualifier: 当有多个同一类型的bean时,可以用@Qualifier("name")来指定

@Resource : java提供

切面(AOP)相关注解:

@Aspect:声明一个切面

@After:在方法执行后执行(方法上)

@Before:在方法上执行前执行(方法上)

@Around:在方法执行前与执行后执行(方法上)

@PointCut:声明切点

@EnableAspectJAutoProxy:开启Spring对AspectJ代理的支持

SpringMVC常用注解:

@RestController:该注解为一个组合注解,相当于@Controller和@ResponseBody的组合,注解在类上,意味着,该Controller的所有方法都默认加上了@ResponseBody

@RequestMapping:用于映射web请求,包括访问路径和参数

@ResponseBody:支持request的参数在request体中,而不是在呢直接连接的地址后面

其他注解:
@JsonFormat
此注解用于属性或者方法上(最好是属性上),可以方便的把 Date 类型直接转
化为我们想要的模式.
@Transactional 注解放在类级别时,表示所有该类的公共方法都配置相同的事
务属性信息。
SpringBoot 注解:
@SpringBootApplication:
包含@Configuration、@EnableAutoConfiguration、@ComponentScan 通
常用在主类上;
@RestControllerAdvice,@ExceptionHandler 用于统一异常处理,捕获指定的
异常.
配置类相关注解:
@Configuration:声明当前类为配置类
@Bean:注解在方法上,声明当前方法的返回值为一个 bean,替代 xml 中的
方式
@ComponentScan:用于对 Component 类型注解进行扫描

SpringBoot自动装配原理

1.注解层面梳理

2.run()方法层面梳理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吃橘子的Crow

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值