Spring IoC和AOP的介绍
本文内容纲要:
- 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。实际上这就是观察者模式。
可以在容器中配置监听器以启动容器
1 <context-param>2 <param-name>contextConfigLocation</param-name>
3 <param-value> /WEB-INF/applicationContext.xml</param-value>
4 </context-param>
5
6 <listener>
7 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
8 </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》
本文内容总结:IoC,AOP,
原文链接:https://www.cnblogs.com/bigshark/p/7979324.html
以上是 Spring IoC和AOP的介绍 的全部内容, 来源链接: utcz.com/z/296564.html