Spring IoC和AOP的介绍
基于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的介绍的更多相关文章
- 【转】spring - ioc和aop
[转]spring - ioc和aop 1.程序中为什么会用到spring的ioc和aop 2.什么是IOC,AOP,以及使用它们的好处,即详细回答了第一个问题 3.原理 关于1: a:我们平常使用对 ...
- J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP
J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP 前言 搜狐畅游笔试题中有一道问答题涉及到回答谈谈对Spring IOC与AOP的理解.特将相关内容进行整理. ...
- BeanPostProcessor —— 连接Spring IOC和AOP的桥梁
之前都是从大Boss的视角,来介绍Spring,比如IOC.AOP. 今天换个视角,从一个小喽啰出发,来加深对Spring的理解. 这个小喽啰就是, BeanPostProcessor (下面简称 B ...
- Spring IOC模块的简单介绍
首先,本人正在学习spring,这是一点心得体会,所以本文中会有不足.错误之处,欢迎各位大佬进行指点. 其次对于框架而言,知道反射是很重要,所以建议在学会反射了后在去看看框架. Spring:是企业级 ...
- spring - ioc和aop
1.程序中为什么会用到spring的ioc和aop 2.什么是IOC,AOP,以及使用它们的好处,即详细回答了第一个问题 3.原理 关于1: a:我们平常使用对象的时候,一般都是直接使用关键字类new ...
- Spring IOC及AOP学习总结
一.Spring IOC体系学习总结: Spring中有两个容器体系,一类是BeanFactory.还有一类是ApplicationContext.BeanFactory提供了基础的容器功能.Appl ...
- Spring ioc与aop的理解
一 spring的特点 1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦 2.可以使用容易提供的众多服务,如事务管理,消息服务等 3.容器提供单例模式支持 4.容器提供了AOP技术,利用它很容易 ...
- spring IOC与AOP
Spring IOC容器 spring IOC 容器有两种,分别是 BeanFactory 容器和 ApplicationContext 容器. BeanFactory如下: /*第一步,利用Clas ...
- Spring IOC、AOP、Transaction、MVC小结
1.IOC.AOP:把对象交给Spring进行管理,通过面向切面编程来实现一些“模板式”的操作,使得程序员解放出来,可以更多的关注业务实现. - ...
随机推荐
- Linux下查看CPU使用率 --- top命令的使用
在系统维护的过程中,随时可能有需要查看 CPU 使用率,并根据相应信息分析系统状况的需要.在 CentOS 中,可以通过 top 命令来查看 CPU 使用状况.运行 top 命令后,CPU 使用状态会 ...
- C# 中out 参数 和 ref参数的区别
C#中共有4种参数类型,分别是 传值(by value), 传址 (by reference), 输出参数 (by output), 数组参数 (by array) by value => 传值 ...
- 解决IIS出现的问题
- Dropout和学习率衰减
Dropout 在机器学习的模型中,如果模型的参数太多,而训练样本又太少,训练出来的模型很容易产生过拟合的现象.在训练神经网络的时候经常会遇到过拟合的问题,过拟合具体表现在:模型在训练数据上 ...
- Codeforces - 102222H - Fight Against Monsters - 贪心
https://codeforc.es/gym/102222/problem/H 题意:有一堆怪兽,怪兽有HP和ATK.你有一个英雄,英雄每次先被所有怪兽打,然后打其中一个怪兽.打的伤害递增,第一次1 ...
- 打通Java与MySQL的桥梁——jdbc
实现的基本步骤: 1.加载驱动程序: Class.forName("com.mysql.jdbc.Driver"); 2.获得数据可连接: private static final ...
- “Enterprise Architect”和数据库的不解之缘
前言 在这个大数据盛行的时代,和数据打交道变的必不可少了,所有如果有工具来规范我们的数据库会更加方便我们的生活.这次机房,我们利用EA(Enterprise Architect)自动生成SQL语句来达 ...
- 自定义标签报 无法为TAG [my2:hello]加载标记处理程序类[null]
今天练习jsp自定义标签的时候,等我写好全部和检查万无一失的时候.执行然后报错了 无法为TAG [my2:hello]加载标记处理程序类[null] 我反复检查代码,发现代码也没什么问题.后面通过百度 ...
- AX 2012 窗体增加分隔线
在AX中将窗体控件分区一般通过group来实现,但是类似salesTable的可以调整大小的分区其实也是用group控件再加一些方法实现的. 1, 留意splitGroup属性: Autodeclar ...
- python 3.x 安装问题及连接oracle数据库
最近有用到python去处理一些问题,发现现在3已出来,遂用直接下3.7使用 发现问题还是有一点的 1. pip 会出现ssl问题 Could not install packages due to ...