一:前言

Spring 有XML配置和注解两种版本,我个人非常喜欢使用注解,相当热衷Spring boot!

对于Spring,核心就是IOC容器,这个容器说白了就是把你放在里面的对象(Bean)进行统一管理,你不用考虑对象如何创建如何销毁,从这方面来说,所谓的控制反转就是获取对象的方式被反转了。

既然你都把对象交给人家Spring管理了,那你需要的时候不得给人家要呀。这就是依赖注入(DI)!再想下,我们在传入一个参数的时候除了在构造方法中就是在setter方法中,换个好听的名字就是构造注入设值注入

至于AOP(面向切面),这玩意我举个例子说下,比如你写了个方法用来做一些事情,但这个事情要求登录用户才能做,你就可以在这个方法执行前验证一下,执行后记录下操作日志,把前后的这些与业务逻辑无关的代码抽取出来放一个类里,这个类就是切面(Aspect),这个被环绕的方法就是切点(Pointcut),你所做的执行前执行后的这些方法统一叫做增强处理(Advice)。

二:配置

推荐使用IDEA快速构建Spring项目!

抛弃配置第一步,快速定义application.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">

    <!--开启自动扫描-->
    <context:component-scan base-package="cn.zyzpp"/>

</beans>

作用

  1. 默认扫描Spring提供的@Component, @Repository, @Service,@Controller、@RestController、@ControllerAdvice和@Configuration等注解的类。
  2. 默认开启annotation注解配置,激活@Required,@Autowired, @PostConstruct, @PreDestroy, @Resource, @PersistenceContext, @PersistenceUnit组件类中的注释。

三:依赖注入

搜索Bean类

Spring提供如下几个Annotation来标注Spring Bean:

  • @Component: 标注一个普通的Spring Bean类
  • @Controller: 标注一个控制器组件类
  • @Service: 标注一个业务逻辑组件类
  • @Repository: 标注一个DAO组件类

使用@Resource配置依赖

使用@Resource<property.../>元素的ref属性有相同的效果。

@Resource不仅可以修饰setter方法,也可以直接修饰实例变量,如果使用@Resource修饰实例变量将会更加简单,此时Spring将会直接使用JavaEE规范的Field注入,此时连setter方法都可以不要。

@Resource位于javax.annotation包下,是来自JavaEE规范的一个Annotation

@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。

使用@Autowired配置依赖

Spring提供了@Autowired注解来指定自动装配,@Autowired可以修饰setter方法、普通方法、实例变量和构造器等。当使用@Autowired标注setter方法时,默认采用byType自动装配策略。

默认情况下@Autowired(required = true),意思是要求依赖对象必须存在。

搭配@Qualifier指定BeanId

在这种策略下,符合自动装配类型的候选Bean实例常常有多个,这个时候就可能引起异常,为了实现精确的自动装配,Spring提供了@Qualifier注解,通过使用@Qualifier,允许根据Bean的id来执行自动装配。

    @Autowired
    @Qualifier(value = "user")
    User user;

四:定义Bean

@Configuration配置

@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。

 @Configuration
 public class AppConfig {

     @Autowired
     Environment env;

     @Bean
     public MyBean myBean() {
         MyBean myBean = new MyBean();
         myBean.setName(env.getProperty("bean.name"));
         return myBean;
     }
 }

@Bean定义

@Bean 与 Component 的区别是用在方法上 ,而不是类上。类似于XML中 <bean/> 。默认Bean名称为方法名。

如果需要显式命名,可以使用name属性(或value属性)。还要注意,name接受字符串数组,允许对单个bean使用多个名称(即主bean名称加上一个或多个别名)。

可以定义Bean的初始化方法与关闭应用程序时调用的方法。

     @Bean({"b1", "b2"},initMethod = "",destroyMethod = "") // 有b1,b2 bean,但没有myBean
     public MyBean myBean() {
         return new MyBean;
     }

@Scope作用域

@Scope可以搭配@Component等或者@Bean注解定义Bean的作用域。默认作用域 Singleton。

作用域 描述
singleton 在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,默认值
prototype 每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()
request 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
session 同一个HTTP Session共享一个Bean,不同Session使用不同的Bean,仅适用于WebApplicationContext环境
global-session 一般用于Portlet应用环境,改作用于仅适用于WebApplicationContext环境

示例

@Component
@Scope(value = "singleton")
public class HelloWord {

@Lazy懒加载

@Lazy搭配@Component或@Bean使用,作用是延迟初始化 bean,告诉IOC 容器在它第一次被请求时,而不是在启动时去创建一个 bean 实例。

@Component
@Lazy
public class HelloWord {

@PostConstruct和@PreDestroy定制生命周期行为

@PostConstruct@PreDestroy同样位于javax.annotation包下,也是来自JavaEE规范的两个Annotation,Spring直接借鉴了它们,用于定制Spring容器中Bean的生命周期行为。

它们都用于修饰方法,无须任何属性。

其中前者修饰的方法时Bean的初始化方法;而后者修饰的方法时Bean销毁之前的方法。

五:使用AOP

AOP(Aspect Orient Programming)也就是面向切面编程,作为面向对象编程的一种补充,已经成为一种比较成熟的编程方式。其实AOP问世的时间并不太长,AOP和OOP互为补充,面向切面编程将程序运行过程分解成各个切面。

AOP专门用于处理系统中分布于各个模块(不同方法)中的交叉关注点的问题,在JavaEE应用中,常常通过AOP来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等,AOP已经成为一种非常常用的解决方案。

配置开启AOP

  <!--启动@AspectJ支持-->
  <aop:aspectj-autoproxy/>

  <!--指定自动搜索Bean组件、自动搜索切面类-->
  <context:component-scan base-package="cn.zyzpp">
    <context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
  </context:component-scan>

@Aspect定义切面

@Aspect是不能被扫描到的,所以需要配合@Component注解。@Aspect标识自己是一个切面,将自己从自动代理中删除。

@Aspect
public class AspectModule {
}

@Pointcut定义切点

注意切点通过一个普通方法来定义,返回类型必须为void。支持execution表达式,within表达式,例如:

@Pointcut("execution(* cn.zyzpp.demo.*Word.*(..))")
private void businessService() {}  // signature

第一个*表示任意返回类型,以.号进行划分,接下来是包名,类名,类名后是方法名,方法名跟括号,括号内是参数,两个点..意思是任意参数。

其它用法参考 AOP表达式用法
AspectJ语法详解:execution,within,this,@Aspect

Advice增强处理

注解 解释
@Before 前置通知:目标方法执行之前执行以下方法体的内容
@After 后置通知:目标方法执行之后执行以下方法体的内容,不管是否发生异常。
@AfterReturning 返回通知:目标方法正常执行完毕时执行以下代码
@AfterThrowing 异常通知:目标方法发生异常的时候执行以下代码
@Around 环绕通知:目标方法执行前后分别执行一些代码,发生异常的时候执行另外一些代码

执行顺序

JoinPoint 获取目标方法

访问目标方法最简单的做法是定义增强处理方法时,将第一个参数定义为JoinPoint类型,当该增强处理方法被调用时,该JoinPoint参数就代表了织入增强处理的连接点。JoinPoint里包含了如下几个常用的方法:

  • Object[] getArgs:返回目标方法的参数
  • Signature getSignature:返回目标方法的签名
  • Object getTarget:返回被织入增强处理的目标对象
  • Object getThis:返回AOP框架为目标对象生成的代理对象

自定义注解向Advice传参

@Retention定义自定义注解的生命周期

  1. RetentionPolicy.SOURCE:注解只作用在Java源文件(.java文件) ,不会被编译为Class字节码文件。
  2. RetentionPolicy.CLASS:注解保留到Class文件,在JVM加载Class文件时候被遗弃,为默认生命周期
  3. RetentionPolicy.RUNTIME:注解在源文件与Class中存在,可被JVM加载,在运行时动态获取。

@Target定义注解的作用位置

  • ElementType.TYPE //接口、类、枚举、注解
  • ElementType.FIELD //字段、枚举的常量
  • ElementType.METHOD //方法
  • ElementType.PARAMETER //方法参数
  • ElementType.CONSTRUCTOR //构造函数
  • ElementType.LOCAL_VARIABLE //局部变量
  • ElementType.ANNOTATION_TYPE //注解
  • ElementType.PACKAGE ///包

@Documented,@Inherited 忽略即可!

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Annota {
    String value();
}

在目标方法使用此注解

    @Annota("Mark")
    public void say(String name){
        ....
    }

完整AOP示例

@Component
@Aspect
public class MyAspect {
    //声明切点
    @Pointcut("execution(* cn.zyzpp.demo.*Word.*(..))")
    public void pointcut(){}

    //声明切点
    @Pointcut("within(cn.zyzpp.demo.*)")
    public void bizPointcut(){}

    //前置通知:目标方法执行之前执行以下方法体的内容
    @Before("pointcut()")
    public void before(){
        System.out.println("    before");
    }

    //前置通知:获取注解,给Advice传递参数
    @Before("pointcut() && @annotation(annota)")
    public void beforeWithAnnotaion(Annota annota) {
        System.out.println("BeforeWithAnnotation: " + annota.value());
    }

    //前置通知:获取参数
    @Before("pointcut()")
    public void beforeArgs(JoinPoint joinPoint){
        for (Object object:joinPoint.getArgs()){
            System.out.println("    before args: "+object.toString());
        }
    }

    //前置通知:获取对象
    @Before("pointcut() && args(arg)")
    public void beforeWithPar(Object arg){
        System.out.println("    before obj: "+arg.toString());
    }

    //后置通知:目标方法执行之后执行以下方法体的内容,不管是否发生异常。
    @After("pointcut()")
    public void after() {
        System.out.println("    After");
    }

    //返回通知::目标方法正常执行完毕时执行以下代码
    @AfterReturning(pointcut="bizPointcut()" ,returning="retrunValue")
    public void afterReturning(Object retrunValue){
        System.out.println("AfterReturning: "+retrunValue);
    }

    //异常通知:目标方法发生异常的时候执行以下代码
    @AfterThrowing(pointcut="pointcut()", throwing="e")
    public void afterThrowing(RuntimeException e) {
        System.out.println(" AfterThrowing: " + e.getMessage());
    }

    //环绕通知:目标方法执行前后分别执行一些代码,发生异常的时候执行另外一些代码
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("  Around: start");
        Object obj = pjp.proceed();
        System.out.println("  Around: end, return: "+obj);
        return obj;
    }

}

六:事物管理

一个数据库事务是一个被视为单一的工作单元的操作序列。这些操作应该要么完整地执行,要么完全不执行。事务管理是一个重要组成部分,RDBMS 面向企业应用程序,以确保数据完整性和一致性。事务的概念可以描述为具有以下四个关键属性说成是 ACID

  • 原子性:事务应该当作一个单独单元的操作,这意味着整个序列操作要么是成功,要么是失败的。
  • 一致性:这表示数据库的引用完整性的一致性,表中唯一的主键等。
  • 隔离性:可能同时处理很多有相同的数据集的事务,每个事务应该与其他事务隔离,以防止数据损坏。
  • 持久性:一个事务一旦完成全部操作后,这个事务的结果必须是永久性的,不能因系统故障而从数据库中删除。

编程式 vs. 声明式

Spring 支持两种类型的事务管理:

  • 编程式事务管理:这意味着你在编程的帮助下有管理事务。这给了你极大的灵活性,但却很难维护。
  • 声明式事务管理 :这意味着你从业务代码中分离事务管理。你仅仅使用注释或 XML 配置来管理事务。

声明式事务管理比编程式事务管理更可取,尽管它不如编程式事务管理灵活,但它允许你通过代码控制事务。

基于注解的方式

1.开启事务

    <!-- 初始化 数据源 -->
    <bean id="dataSource"
          class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/TEST" />
        <property name="username" value="root" />
        <property name="password" value="123456" />
    </bean>
    <!-- 事务管理器配置 -->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!-- 使用annotation注解定义事务 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>

2.service类@Transactional(name=value)

@Transactional参数

参数名称 功能描述
readOnly 该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true)
rollbackFor 该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})
rollbackForClassName 该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:指定单一异常类名称:@Transactional(rollbackForClassName="RuntimeException")指定多个异常类名称:@Transactional(rollbackForClassName={"RuntimeException","Exception"})
noRollbackForClassName 该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:指定单一异常类名称:@Transactional(noRollbackForClassName="RuntimeException")指定多个异常类名称:@Transactional(noRollbackForClassName={"RuntimeException","Exception"})
propagation 该属性用于设置事务的传播行为。例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
isolation 该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置
timeout 该属性用于设置事务的超时秒数,默认值为-1表示永不超时

尾声

本文辛苦码字半天,顺带复习下Spring的知识,流程图用的word~~

本文已授权微信公众号“后端技术精选”独家发布

抛弃配置后的Spring终极教程的更多相关文章

  1. Spring应用教程-3 依赖关系配置

    注:组件与组件之间的耦合,采用依赖注入管理,但普通的JavaBean属性值,应直接在代码中设置. 1. 注入其他Bean的属性值 我们分析一下,Bean_A的一个属性要依赖Bean_B的一个属性值.这 ...

  2. 2017.3.31 spring mvc教程(二)核心流程及配置详解

    学习的博客:http://elf8848.iteye.com/blog/875830/ 我项目中所用的版本:4.2.0.博客的时间比较早,11年的,学习的是Spring3 MVC.不知道版本上有没有变 ...

  3. 【Spring Framework】Spring入门教程(二)基于xml配置对象容器

    基于xml配置对象容器--xml 标签说明 alias标签 作用:为已配置的bean设置别名 --applicationContext.xml配置文件 <?xml version="1 ...

  4. spring boot 教程(三)配置详解

    在大部分情况下,我们不需要做太多的配置就能够让spring boot正常运行.在一些特殊的情况下,我们需要做修改一些配置,或者需要有自己的配置属性. Spring Boot 支持多种外部配置方式 这些 ...

  5. Spring Boot教程(三十二)多数据源配置与使用

    之前在介绍使用JdbcTemplate和Spring-data-jpa时,都使用了单数据源.在单数据源的情况下,Spring Boot的配置非常简单,只需要在application.propertie ...

  6. Spring Boot教程(三十二)多数据源配置与使用(1)

    之前在介绍使用JdbcTemplate和Spring-data-jpa时,都使用了单数据源.在单数据源的情况下,Spring Boot的配置非常简单,只需要在application.propertie ...

  7. 【Spring Framework】Spring入门教程(三)使用注解配置

    本文主要介绍四个方面: (1) 注解版本IOC和DI (2) Spring纯注解 (3) Spring测试 (4) SpringJDBC - Spring对数据库的操作 使用注解配置Spring入门 ...

  8. Spring MVC 教程,快速入门,深入分析

    http://elf8848.iteye.com/blog/875830/ Spring MVC 教程,快速入门,深入分析 博客分类: SPRING Spring MVC 教程快速入门  资源下载: ...

  9. Spring Security教程系列(一)基础篇-1

    第 1 章 一个简单的HelloWorld 第 1 章 一个简单的HelloWorld Spring Security中可以使用Acegi-1.x时代的普通配置方式,也可以使用从2.0时代才出现的命名 ...

随机推荐

  1. Node.js学习记录(一)--安装设置篇

    安装Node window window上安装node可选择以下两种方式: 方式一:直接进入官网下载安装 进入node.js官网点击windows,选择.msi后缀的,根据自己的电脑选择对应的64位或 ...

  2. Scala并发编程【快速入门】

    1.简介 Scala的actor提供了一种基于事件的轻量级线程.只要使用scala.actors.Actor伴生对象的actor()方法,就可以创建一个actor.它接受一个函数值/闭包做参数,一创建 ...

  3. sublime text 3 优化配置

    目录 1. sublime text 3 模板插件 SublimeTmpl 配置 修改模板内容格式 修改快捷键 2. 设置sublime text的 TAB 为4个空格 3. 添加markdown支持 ...

  4. Could not update the distribution database subscription table. The subscription status could not be changed.

    在一个测试服务器删除发布(Publication)时遇到下面错误,具体如下所示 标题: Microsoft SQL Server Management Studio   --------------- ...

  5. Android内嵌VLC实现播放网络视频,网络音频

    1.在对应模块的build.gradle文件中,添加依赖 //VlC implementation "de.mrmaffen:vlc-android-sdk:2.0.6" 2.布局 ...

  6. Apache中httpd.conf文件的详解

    PHP中,Apache的配置至关重要,特别是httpd.conf这个文件,它是Apache中的核心文件.好了,废话不说,今天将这个文件中的一些内容讲解一番. ServerRoot "d:/w ...

  7. LeetCode算法题-Valid Perfect Square(Java实现-四种解法)

    这是悦乐书的第209次更新,第221篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第77题(顺位题号是367).给定正整数num,写一个函数,如果num是一个完美的正方形 ...

  8. June 6. 2018 Week 23rd Wednesday

    You are confined only by the walls you build yourself. 限制你的只有你自己筑起的墙. From Andrew Murphy. Let's repe ...

  9. 力扣算法题—051N皇后问题

    #include "000库函数.h" //使用回溯法来计算 //经典解法为回溯递归,一层一层的向下扫描,需要用到一个pos数组, //其中pos[i]表示第i行皇后的位置,初始化 ...

  10. [福大软工] Z班 第4次成绩排行榜

    作业要求 http://www.cnblogs.com/easteast/p/7511234.html 评分细则 (1)博客--15分,分数组成如下: 随笔开头,给出结队两个同学的学号.PS:结对成员 ...