基于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. 第三周作业-课本&&视频学习

    <网络攻防技术与实践>第三周作业 Part I 寻找自己留在互联网上的足迹并消除隐私 1.1 google/baidu搜索自己的qq号 搜索结果如图,搜到的有用信息其实就是图上这么几条,能 ...

  2. 新建用户无法通过SecureSRT进行ssh登录到远程linux (zz)

    root新建了一个普通用户oracle,并且设置了密码:通过SecureSRT连接远程linux,连不上[注:用的是之前新建过的以root为用户名的SecureSRT已有连接,如192.168.1.1 ...

  3. C#在Linux上的开发指南(续)

    续之前的一篇开发指南http://www.cnblogs.com/RainbowInTheSky/p/5496777.html 部分人在部署的时候经常出现dll兼容问题(其实可以看小蝶惊鸿的文章,蝶神 ...

  4. Struts2 源码分析-----拦截器源码解析 --- ParametersInterceptor

    ParametersInterceptor拦截器其主要功能是把ActionContext中的请求参数设置到ValueStack中,如果栈顶是当前Action则把请求参数设置到了Action中,如果栈顶 ...

  5. Cogs 1264. [NOIP2012] 开车旅行(70分 暴力)

    1264. [NOIP2012] 开车旅行 ★★☆   输入文件:drive.in   输出文件:drive.out   简单对比时间限制:2 s   内存限制:128 MB [题目描述] 小A 和小 ...

  6. this android sdk requires android developer toolkit version

    this android sdk requires android developer toolkit version 10.0.0 or above. current version is 8.0. ...

  7. App渠道统计方法全面解析 总有一种适合你

    一.App渠道统计对于App推广运营的重要性 (理解App渠道统计重要性的老司机,请直接移步到第二部分) App服务的竞争重点已经由功能竞争转向市场和运营的竞争,而App的推广与运营离不开App渠道统 ...

  8. C 语言实例 - 创建各类三角形图案

    C 语言实例 - 创建各类三角形图案 创建三角形图案. 实例 - 使用 * 号 #include <stdio.h> int main() { int i, j, rows; printf ...

  9. 洛谷P4018 Roy&October之取石子

    题目背景 \(Roy\)和\(October\)两人在玩一个取石子的游戏. 题目描述 游戏规则是这样的:共有\(n\)个石子,两人每次都只能取\(p^k\)个(\(p\)为质数,\(k\)为自然数,且 ...

  10. 自定义ClassLoader加载加密的class文件

    package com.yd.wmsc.util; public class Test { public void say(){ System.out.println("Say Hello& ...