基于Spring Framework 版本:5.0.2.RELEASE


IoC

概念:传统Java开发中,程序通过new主动创建对象实例,而Spring有专门的IoC容器来创建对象,具体来说就是在Spring容器中注册过的类,其创建、销毁等过程交由Spring来统一负责管理,所以这一过程也叫依赖注入(DI)。

Spring的基础IoC容器包是org.springframework.beans和org.springframework.context。

核心接口

BeanFactory接口作为容器的根接口,提供Bean的一些基础定义和方法;

ApplicationContext是BeanFactory的子接口,为应用程序提供了更丰富的功能。

BeanFactory、ApplicationContext之间的继承关系如下图

注入方式

Spring的主要有两种注入方式:构造器注入、Setter方法注入。如何选择呢?

  • Spring推荐使用构造器注入,因为构造器注入时,component组件可以当作不可变对象,并且能确保其不为空,而且构造器注入的component返回时是完全初始化的状态。
  • 当一个类中需要注入太多的参数时,可能这个类负责了太多的功能,可以考虑适当的重构。
  • Setter方法注入可以作为备选方案,但是如果没有默认值时最好进行非空检查。
  • Setter注入的一个好处是类的对象能够在后来重新配置或重新注入。
  • 如果使用的第三方源码不提供Setter方法时,就只能选择构造器注入的方式了。
  • 构造器注入可能引入循环依赖问题。比如:A类构造器注入B,B类构造器注入A,此时Spring容器会抛出异常BeanCurrentlyInCreationException。此时需要考虑使用Setter方法注入的方式了。

配置方法

Spring常用XML和注解的方式来配置类,这里推荐使用注解来配置。需要注意的是注解是在XML之前执行注入的,因此后者的配置将覆盖注解的配置。

Bean的作用域和生命周期

Bean的作用域,其中request、Session、application、websocket仅在ApplicationContext上下文才有效。

作用域

描述

singleton

默认值,单例,整个IoC容器只有一个实例对象。

prototype

原型,每次调用都会实例化一个地响。

request

作用于HTTP请求的生命周期,每个HTTP请求都有一个自己的实例。仅在ApplicationContext上下文有效。

session

作用于HTTP Session的生命周期,仅在ApplicationContext上下文有效。

application

作用于ServletContext的生命周期,仅在ApplicationContext上下文有效。

websocket

作用于WebSocket的生命周期,仅在ApplicationContext上下文有效。

Bean的生命周期

过程描述

1.Spring对bean进行实例化;

2.Spring将值和bean的引用注入到bean对应的属性中;

3.如果bean实现了BeanNameAware接口,Spring将bean的ID传递给setBean-Name()方法;

4.如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入;

5.如果bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext()方法,将bean所在的应用上下文的引用传入进来;

6.如果bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessBeforeInitialization()方法;

7.如果bean实现了InitializingBean接口,Spring将调用它们的afterPropertiesSet()方法。类似地,如果bean使用init-method声明了初始化方法,该方法也会被调用;

8.如果bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessAfterInitialization()方法;

9.此时,bean已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁;

10.如果bean实现了DisposableBean接口,Spring将调用它的destroy()接口方法。同样,如果bean使用destroy-method声明了销毁方法,该方法也会被调用。

常用注解说明

@Bean, @Configuration表示基于Java配置的类

@Bean除了配置在@Configuration,也可以在@Component定义,此时没有特殊意义,只是普通的工厂方法。

@Import 导入依赖的类,进行优先注入

@ImportResource 导入依赖的Spring配置

@Value("${jdbc.url}") 可以使用${}动态获取配置参数

@PropertySource 可导入properties配置文件

@Qualifier 指定属性名称

@Autowired和 @Resource

@Autowired通过类型选择Bean,@Resource通过名称选择Bean。

@Resource 是JSR-250注解

@Primary 注入的优先级

@PostConstruct 在初始化时执行的方法

@PreDestroy 在销毁时执行的方法

@Bean(initMethod = "init") @Bean(destroyMethod = "cleanup") 调用初始化和销毁的方法

@Component, @Repository, @Service, @Controller,都是component,所以都可以被scan,一般分别用于标注po、dao、service和controller

Spring MVC 提供@RestController ,它是@Controller 和 @ResponseBody的组合形式。

@ComponentScan (basePackages = "") 扫描component

扫描过滤器使用:@ComponentScan(basePackages = "org.example",  includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),  excludeFilters = @Filter(Repository.class))

  基于XML的配置可以用ClassPathXmlApplicationContext来获取Bean,基于Java的配置可以使用AnnotationConfigApplicationContext,它提供register()注册配置类。

Spring的国际化

当加载一个ApplicationContext时,它会自动搜索上下文中定义的MessageSource bean。bean必须有名称messageSource。如果找到了这样的bean,那么所有对方法的调用都将被委托给消息源。如果没有找到消息源,ApplicationContext将尝试寻找包含同名bean的父类。

Spring提供了一些国际化的实现类,如:ResourceBundleMessageSource

Spring事件

Spring的事件处理是通过ApplicationEvent类和ApplicationListener接口实现的。如果一个实现ApplicationListener接口的bean被部署到上下文中,那么每次应用程序事件被发布到ApplicationContext时,就会通知bean。实际上这就是观察者模式

可以在容器中配置监听器以启动容器

 <context-param>
<param-name>contextConfigLocation</param-name>
<param-value> /WEB-INF/applicationContext.xml</param-value>
</context-param> <listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Resource

Spring提供了更加高级的资源文件处理方法,具体使用可查看API文档

校验、数据绑定、类型转换

Spring实现Validator接口可以非侵入式地校验!另外可以使用这两个类MessageCodesResolver,DefaultMessageCodesResolver来获取国际化错误信息。

Spring提供DataBinder类实现数据绑定的功能。DataBinder和Validator组合,实现Spring的校验包。

Bean包装器BeanWrapper,用来包装Bean,给Bean设置属性。

   BeanWrapper company = new BeanWrapperImpl(new Company());

Spring实现Converter接口、ConverterFactory接口来实现类型转换。

常用的转换器:

通用转换器GenericConverter;

条件转换器ConditionalGenericConverter

门面模式转换器ConversionService

Spring实现Formatter接口、AnnotationFormatterFactory注解格式化接口,实现参数的格式化

举例如下:

@NumberFormat(style=Style.CURRENCY)

@DateTimeFormat(iso=ISO.DATE)

Spring提供注解格式化规则注册类:FormatterRegistry ,FormatterRegistrar

Spring MVC中的格式化类是FormattingConversionServiceFactoryBean

自定义校验注解实现ConstraintValidator


AOP

Aspect-Oriented Programming (AOP) ,OOP的关键模块单元是class,而AOP的关键模块单元是切面。AOP主要可以应用在事务,日志,安全等方面。

 一些概念

  • 切面Aspect:由切面和切点来定义出一个切面;
  • 连接点Join point:执行程序时的一个点,例如执行方法、处理异常、修改字段,这些点可以用来插入切面代码。在Spring AOP中,连接点就是执行方法。
  • 通知Advice:在特定连接点上采取的行动。
  • 切点Pointcut:表达式匹配通知所要织入的一个或多个连接点,是AOP的核心,Spring在默认情况下使用AspectJ切点表达式语言。
  • 引入Introduction:引入允许我们向现有的类添加新方法或属性。Spring AOP允许向任何被通知的对象引入新的接口(以及相应的实现)。(在AspectJ社区中,介绍称为跨类型声明。)
  • 目标对象Target object:被通知的对象,由于Spring AOP是动态代理实现的,所以这个对象将永远是一个代理对象。
  • AOP代理AOP proxy:一个由AOP框架创建的对象,以实现切面约定(通知方法执行等等)。在Spring框架中,AOP代理将是一个JDK动态代理或CGLIB代理。
  • 织入Weaving:把切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。在目标对象的生命周期里有多个点可以进行织入:编译期(AspectJ)、类加载期、运行期(Spring AOP)。

通知类型

  • 前置通知Before advice: 在目标方法被调用之前调用通知功能;
  • 返回通知After returning advice: 在目标方法成功执行之后调用通知;
  • 异常通知After throwing advice: 在目标方法抛出异常后调用通知;
  • 后置通知After (finally) advice: 在目标方法完成之后调用通知,此时不会关心方法的输出是什么;
  • 环绕通知Around advice: 通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。

AOP代理,默认使用标准的JDK动态代理,如果业务对象没有实现接口,则默认使用CGLIB

对于JDK代理,只有在代理上调用的公共接口方法才能被拦截。使用CGLIB,在代理的public和protected方法调用将被拦截,甚至在必要时也可以使用包可见default的方法。

简单使用说明

1、声明切面@Aspect

首先要启用@AspectJ注释

@Configuration

@EnableAspectJAutoProxy

public class AppConfig{ }

2、声明切点@Pointcut

例如:@Pointcut("execution(* transfer(..))")匹配任何名为'transfer'的方法的执行

Spring的PCD支持

Spring不支持AspectJ中的call, get, set, preinitialization, staticinitialization, initialization, handler, adviceexecution, withincode, cflow, cflowbelow, if, @this, @withincode,如果使用了会抛出IllegalArgumentException

Spring AOP支持的PCD(切点指示符):

execution - 匹配执行方法的连接点,Spring是最主要的PCD;

within - 用类型匹配连接点;

this - 指定的Bean引用类型;

target - 指定的对象实例;

args - 指定的类型参数;

@target - 执行对象的类有指定类型的注释;

@args - 实际参数的运行时类型有指定类型的注释;

@within - 在具有指定注释的类型中限制匹配的连接点;

@annotation - 限制的连接点有指定的注释;

Spring AOP还支持bean(idOrNameOfBean)指定Bean的id或名字。

PCD组合使用

切入点表达式可以通过'&&'''和'!'来组合。也可以通过名称引用切入点表达式。举例如下:

@Pointcut("execution(public * *(..))")

private void anyPublicOperation() {}

@Pointcut("within(com.xyz.someapp.trading..*)")

private void inTrading() {}

@Pointcut("anyPublicOperation() && inTrading()")

private void tradingOperation() {}

3、声明通知

@Before

@AfterReturning

@AfterThrowing

@After //After (finally) advice

@Around

Spring代理机制简单说明

    • final方法不能通知;
    • Spring 3.2以后不需要再引用CGLIB包;
    • Spring 4.0以后代理对象的构造器不再被调用两次,因为CGLIB代理实例将通过Objenesis来创建,只有在JVM不允许构造器绕过的情况下才能看到两次调用

强制使用CGLIB方法:@EnableAspectJAutoProxy(proxyTargetClass = true)

 

参考资料

Spring Framework官方文档:https://docs.spring.io/spring/docs/5.0.2.RELEASE/spring-framework-reference/

《Spring In Action》

Spring IoC和AOP的介绍的更多相关文章

  1. 【转】spring - ioc和aop

    [转]spring - ioc和aop 1.程序中为什么会用到spring的ioc和aop 2.什么是IOC,AOP,以及使用它们的好处,即详细回答了第一个问题 3.原理 关于1: a:我们平常使用对 ...

  2. J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP

    J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP 前言   搜狐畅游笔试题中有一道问答题涉及到回答谈谈对Spring IOC与AOP的理解.特将相关内容进行整理.    ...

  3. BeanPostProcessor —— 连接Spring IOC和AOP的桥梁

    之前都是从大Boss的视角,来介绍Spring,比如IOC.AOP. 今天换个视角,从一个小喽啰出发,来加深对Spring的理解. 这个小喽啰就是, BeanPostProcessor (下面简称 B ...

  4. Spring IOC模块的简单介绍

    首先,本人正在学习spring,这是一点心得体会,所以本文中会有不足.错误之处,欢迎各位大佬进行指点. 其次对于框架而言,知道反射是很重要,所以建议在学会反射了后在去看看框架. Spring:是企业级 ...

  5. spring - ioc和aop

    1.程序中为什么会用到spring的ioc和aop 2.什么是IOC,AOP,以及使用它们的好处,即详细回答了第一个问题 3.原理 关于1: a:我们平常使用对象的时候,一般都是直接使用关键字类new ...

  6. Spring IOC及AOP学习总结

    一.Spring IOC体系学习总结: Spring中有两个容器体系,一类是BeanFactory.还有一类是ApplicationContext.BeanFactory提供了基础的容器功能.Appl ...

  7. Spring ioc与aop的理解

    一 spring的特点 1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦 2.可以使用容易提供的众多服务,如事务管理,消息服务等 3.容器提供单例模式支持 4.容器提供了AOP技术,利用它很容易 ...

  8. spring IOC与AOP

    Spring IOC容器 spring IOC 容器有两种,分别是 BeanFactory 容器和 ApplicationContext 容器. BeanFactory如下: /*第一步,利用Clas ...

  9. Spring IOC、AOP、Transaction、MVC小结

    1.IOC.AOP:把对象交给Spring进行管理,通过面向切面编程来实现一些“模板式”的操作,使得程序员解放出来,可以更多的关注业务实现.                             - ...

随机推荐

  1. Spring入门第一课

    今天先不讲Spring是什么. Spring网址:http://projects.spring.io/spring-framework/ Eclipse 安装开发IDE 在Eclipse Market ...

  2. 【Qt官方例程学习笔记】Raster Window Example(画笔的平移/旋转/缩放应用)

    这个例子显示了如何使用QPainter渲染一个简单的QWindow. 值得学习的内容 <QtGui>头文件 #include <QtGui>就可以使用Qt GUI模块中的所有类 ...

  3. Java数组转置

    数组转置,就是将打印的数组的列和行进行位置对换. 我们就可以用两个for循环遍历数组,然后交换arr[i][j]与arr[j][i] public class Demo{ public static ...

  4. WPF的TextBox产生内存泄露的情况

    前段时间参与了一个WPF编写的项目,在该项目中有这样一个场景:在程序运行过程中需要动态地产生大量文本信息,并追加WPF界面上的一个TextBox的Text中进行显示.编写完之后,运行该项目的程序,发现 ...

  5. Git Reference

    Installing and upgrading Git https://confluence.atlassian.com/bitbucketserver056/installing-and-upgr ...

  6. Git练习1

  7. 消息中间件 | 消息协议 | MQTT3.1.1 -- 《分布式 消息中间件实践》笔记

    1999年,IBM和合作伙伴共同发明MQTT协议 14年,MQTT正式成为推荐的物联网传输协议标准 常应用于很多机器计算能力有限.底带宽.网络不可靠的远程通信应用场景中.   主要概念     MQT ...

  8. 原生JS实现日历

    这周写自己的项目发现又用到日历了,加之自己毕业之后的第一个工作中遇到的任务也是需要写个日历(组员写了,我就不用写了) 今天就来好好折腾一下日历是怎么写的. 首先,我们看看 windows 的日历.发现 ...

  9. Ubuntu下rsyslog审计用户bash操作命令、收集、写入MySQL

    服务端 2台服务端:10.25.109.64.10.45.18.133 1.rsyslog最新版本安装 sudo add-apt-repository ppa:adiscon/v8-stable su ...

  10. CCF201612-1 中间数(二分思想)

    问题链接:CCF201612试题. .对n个数进行排序,找出中间那个数,然后将中间那个数的左右与其相等的数去掉,看左右剩下的数个数是否相等,如果相等则中间那个数就是答案,否在输出-1. 问题描述 问题 ...