Spring源代码解析
Spring源码解析之BeanFactoryPostProcessor(一)

Spring源码解析之BeanFactoryPostProcessor(⼀)BeanFactoryPostProcessor在前⾯⼏个章节,笔者有介绍过BeanFactoryPostProcessor接⼝,在spring在解析BeanDefinition之后,根据BeanDefinition初始化bean之前,会回调我们编写的BeanFactoryPostProcessor实现类并调⽤postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)⽅法,spring会通过这个⽅法传⼊⼀个ConfigurableListableBeanFactory对象,我们可以对这个bean⼯⼚对象新增或修改BeanDefinition。
spring初始化bean⼀个典型的流程,就是根据我们标记在类上的@Component⽣成⼀个BeanDefinition,BeanDefinition中包含这个类的class对象,然后根据class对象⽣成实例。
如果我们编写两个Service:UserService和OrderService,并在类上标注@Component,再编写⼀个BeanFactoryPostProcessor接⼝,在接⼝中我们拿到UserService的BeanDefinition,并修改class为OrderService,那么我们从spring容器中获取userService这个bean,它的类型是UserService呢还是OrderService呢?来看下⾯的⽰例:package org.example.service;import ponent;@Componentpublic class OrderService {}package org.example.service;import ponent;@Componentpublic class UserService {}在Test1BeanFactoryPostProcessor类中,我们获取userService的BeanDefinition,并打印它的class对象,这⾥应该是UserService,然后我们再设置BeanDefinition的class为OrderServiceTest1BeanFactoryPostProcessor.javapackage org.example.service;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanFactoryPostProcessor;import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;import org.springframework.context.annotation.ScannedGenericBeanDefinition;import ponent;@Componentpublic class Test1BeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {ScannedGenericBeanDefinition beanDefinition = (ScannedGenericBeanDefinition) beanFactory.getBeanDefinition("userService");System.out.println("UserService beanDefinition class:" + beanDefinition.getBeanClass());beanDefinition.setBeanClass(OrderService.class);}}MyConfig.javapackage org.example.config;import ponentScan;import org.springframework.context.annotation.Configuration;@Configuration@ComponentScan("org.example.service")public class MyConfig {}测试⽤例:@Testpublic void test01() {ApplicationContext ac = new AnnotationConfigApplicationContext(MyConfig.class);System.out.println("userService class:" + ac.getBean("userService").getClass());}运⾏结果:UserService beanDefinition class:class erServiceuserService class:class org.example.service.OrderService可以看到,spring容器会回调我们编写的bean⼯⼚后置处理器BeanFactoryPostProcessor实现类Test1BeanFactoryPostProcessor ,在回调⽅法中,我们可以从bean⼯⼚获取spring容器已经解析的UserService对应的BeanDefinition对象,打印这个BeanDefinition对象的class对象也确实是UserService的class对象,之后我们修改UserService对应的BeanDefinition的class对象为OrderService的class对象,之后我们从spring容器获取beanName为userService的bean可以看到bean的实现类已经被替换成OrderService对象。
spring源码解析(一)---占位符解析替换

spring源码解析(⼀)---占位符解析替换⼀、结构类图①、PropertyResolver : Environment的顶层接⼝,主要提供属性检索和解析带占位符的⽂本。
bean.xml配置中的所有占位符例如${}都由它解析②、ConfigurablePropertyResolver : 该接⼝定义了如何对组件本⾝进⾏配置。
如:刚刚提到获取value时可以指定任意类型,这依赖于ConversionService进⾏类型转换,当前接⼝就提供了对ConversionService的设置和获取。
另外,可以配置属性占位符的格式,包括:占位符前缀(默认为"${")、占位符后缀(默认为"}")、占位符值分隔符(默认为":",⽤于分隔propertyName和defaultValue)。
组件还可以设置哪些属性是必须存在的,还可以校验必须存在的属性是否真的存在(不存在的话会抛出异常)③、AbstractPropertyResolver : 实现了ConfigurablePropertyResolver接⼝的所有⽅法④、PropertySourcesPropertyResolver : 以PropertySources属性源集合(内部持有属性源列表List<PropertySource>)为属性值的来源,按序遍历每个PropertySource,获取到⼀个⾮null的属性值则返回⼆、demo⽰例public static void main(String[] args) {Properties properties = System.getProperties();properties.setProperty("prefixName", "read-code");ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:${prefixName}-spring.xml");ReadCodeService readCodeService = (ReadCodeService) ac.getBean("readCodeService");readCodeService.say();}View Code三、源码剖析1、⼊⼝ :ClassPathXmlApplicationContext构造函数setConfigLocationspublic ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)throws BeansException {super(parent);setConfigLocations(configLocations);if (refresh) {refresh();}}2、AbstractRefreshableConfigApplicationContext①、ClassPathXmlApplicationContext构造函数调⽤它的基类AbstractRefreshableConfigApplicationContext.setConfigLocations/*** Set the config locations for this application context.* <p>If not set, the implementation may use a default as appropriate.*/public void setConfigLocations(String... locations) {if (locations != null) {Assert.noNullElements(locations, "Config locations must not be null");this.configLocations = new String[locations.length];for (int i = 0; i < locations.length; i++) {this.configLocations[i] = resolvePath(locations[i]).trim(); // 解析路劲}}else {this.configLocations = null;}}②、解析路劲/*** Resolve the given path, replacing placeholders with corresponding* environment property values if necessary. Applied to config locations.* @param path the original file path* @return the resolved file path* @see org.springframework.core.env.Environment#resolveRequiredPlaceholders(String)*/protected String resolvePath(String path) {return getEnvironment().resolveRequiredPlaceholders(path);}3、AbstractPropertyResolverpublic String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {if (this.strictHelper == null) {this.strictHelper = createPlaceholderHelper(false);}return doResolvePlaceholders(text, this.strictHelper);}上述⽅法主要做了两件事 :①、初始化占位符解析器createPlaceholderHelper : 主要是初始化占位符的常量,eg : 前缀 ${ 后缀} and so on②、调⽤私有⽅法---替换占位符具体值private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {return helper.replacePlaceholders(text, new PropertyPlaceholderHelper.PlaceholderResolver() {@Overridepublic String resolvePlaceholder(String placeholderName) {return getPropertyAsRawString(placeholderName);}});}4、占位符 key - > value ,实现PropertyPlaceholderHelper内部接⼝PlaceholderResolver⽅法resolvePlaceholder。
Spring源代码解析(十):Spring Acegi框架授权的实现

Spring源代码解析(十):Spring Acegi框架授权的实现我们从FilterSecurityInterceptor我们从入手看看怎样进行授权的:Java代码1.//这里是拦截器拦截HTTP请求的入口2. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)3. throws IOException, ServletException {4. FilterInvocation fi = new FilterInvocation(request, response, chain);5. invoke(fi);6. }7.//这是具体的拦截调用8. public void invoke(FilterInvocation fi) throws IOException,ServletException {9. if ((fi.getRequest() != null) && (fi.getRequest().getAttribute(FILTER_APPLIED) != null)10. && observeOncePerRequest) {11. //在第一次进行过安全检查之后就不会再做了12. fi.getChain().doFilter(fi.getRequest(), fi.getResponse());13. } else {14. //这是第一次收到相应的请求,需要做安全检测,同时把标志为设置好 - FILTER_APPLIED,下次就再有请求就不会作相同的安全检查了15. if (fi.getRequest() != null) {16. fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);17. }18. //这里是做安全检查的地方19. InterceptorStatusToken token = super.beforeInvocation(fi);20. //接着向拦截器链执行21. try {22. fi.getChain().doFilter(fi.getRequest(), fi.getResponse());23. } finally {24. super.afterInvocation(token, null);25. }26. }27. }我们看看在AbstractSecurityInterceptor是怎样对HTTP请求作安全检测的:Java代码1.protected InterceptorStatusToken beforeInvocation(Object object) {2. Assert.notNull(object, "Object was null");3.4. if (!getSecureObjectClass().isAssignableFrom(object.getClass())) {5. throw new IllegalArgumentException("Security invocationattempted for object "6. + object.getClass().getName()7. + " but AbstractSecurityInterceptor only configuredto support secure objects of type: "8. + getSecureObjectClass());9. }10. //这里读取配置FilterSecurityInterceptor的ObjectDefinitionSource属性,这些属性配置了资源的安全设置11. ConfigAttributeDefinition attr = this.obtainObjectDefinitionSource().getAttributes(object);12.13. if (attr == null) {14. if(rejectPublicInvocations) {15. throw new IllegalArgumentException(16. "No public invocations are allowed via this AbstractSecurityInterceptor. "17. + "This indicates a configuration error becausethe "18. + "AbstractSecurityInterceptor.rejectPublicInvocations property is set to 'true'");19. }20.21. if (logger.isDebugEnabled()) {22. logger.debug("Public object - authentication not attempted");23. }24.25. publishEvent(new PublicInvocationEvent(object));26.27. return null; // no further work post-invocation28. }29.30.31. if (logger.isDebugEnabled()) {32. logger.debug("Secure object: " + object.toString() + ";ConfigAttributes: " + attr.toString());33. }34. //这里从SecurityContextHolder中去取Authentication对象,一般在登录时会放到SecurityContextHolder中去35. if (SecurityContextHolder.getContext().getAuthentication()== null) {36. credentialsNotFound(messages.getMessage("AbstractSecurityInterceptor.authenticationNotFound",37. "An Authentication object was not found in theSecurityContext"), object, attr);38. }39.40. // 如果前面没有处理鉴权,这里需要对鉴权进行处理41. Authentication authenticated;42.43. if (!SecurityContextHolder.getContext().getAuthentication().isAuthenticated() || alwaysReauthenticate) {44. try {//调用配置好的AuthenticationManager处理鉴权,如果鉴权不成功,抛出异常结束处理45. authenticated = this.authenticationManager.authenticate(SecurityContextHolder.getContext()46..getAuthentication());47. } catch (AuthenticationException authenticationException) {48. throw authenticationException;49. }50.51. // We don't authenticated.setAuthentication(true), because each provider should do that52. if (logger.isDebugEnabled()) {53. logger.debug("Successfully Authenticated: " + authenticated.toString());54. }55. //这里把鉴权成功后得到的Authentication保存到SecurityContextHolder中供下次使用56. SecurityContextHolder.getContext().setAuthentication(authenticated);57. } else {//这里处理前面已经通过鉴权的请求,先从SecurityContextHolder中去取得Authentication58. authenticated = SecurityContextHolder.getContext().getAuthentication();59.60. if (logger.isDebugEnabled()) {61. logger.debug("Previously Authenticated: " + authenticated.toString());62. }63. }64.65. // 这是处理授权的过程66. try {67. //调用配置好的AccessDecisionManager来进行授权68. this.accessDecisionManager.decide(authenticated, object, attr);69. } catch (AccessDeniedException accessDeniedException) {70. //授权不成功向外发布事件71. AuthorizationFailureEvent event = new AuthorizationFailureEvent(object, attr, authenticated,72. accessDeniedException);73. publishEvent(event);74.75. throw accessDeniedException;76. }77.78. if (logger.isDebugEnabled()) {79. logger.debug("Authorization successful");80. }81.82. AuthorizedEvent event = new AuthorizedEvent(object, attr, authenticated);83. publishEvent(event);84.85. // 这里构建一个RunAsManager来替代当前的Authentication对象,默认情况下使用的是NullRunAsManager会把SecurityContextHolder中的Authentication对象清空86. Authentication runAs = this.runAsManager.buildRunAs(authenticated, object, attr);87.88. if (runAs == null) {89. if (logger.isDebugEnabled()) {90. logger.debug("RunAsManager did not change Authentication object");91. }92.93. // no further work post-invocation94. return new InterceptorStatusToken(authenticated, false,attr, object);95. } else {96. if (logger.isDebugEnabled()) {97. logger.debug("Switching to RunAs Authentication: "+ runAs.toString());98. }99.100. SecurityContextHolder.getContext().setAuthenticati on(runAs);101.102. // revert to token.Authenticated post-invocation103. return new InterceptorStatusToken(authenticated, t rue, attr, object);104. }105.}到这里我们假设配置AffirmativeBased作为AccessDecisionManager:Java代码1.//这里定义了决策机制,需要全票才能通过2. public void decide(Authentication authentication, Object object, ConfigAttributeDefinition config)3. throws AccessDeniedException {4. //这里取得配置好的迭代器集合5. Iterator iter = this.getDecisionVoters().iterator();6. int deny = 0;7. //依次使用各个投票器进行投票,并对投票结果进行计票8. while (iter.hasNext()) {9. AccessDecisionVoter voter = (AccessDecisionVoter) iter.next();10. int result = voter.vote(authentication, object, config);11. //这是对投票结果进行处理,如果遇到其中一票通过,那就授权通过,如果是弃权或者反对,那就继续投票12. switch (result) {13. case AccessDecisionVoter.ACCESS_GRANTED:14. return;15.16. case AccessDecisionVoter.ACCESS_DENIED:17. //这里对反对票进行计数18. deny++;19.20. break;21.22. default:23. break;24. }25. }26. //如果有反对票,抛出异常,整个授权不通过27. if (deny > 0) {28. throw new AccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied",29. "Access is denied"));30. }31.32. // 这里对弃权票进行处理,看看是全是弃权票的决定情况,默认是不通过,由allowIfAllAbstainDecisions变量控制33. checkAllowIfAllAbstainDecisions();34. }35.具体的投票由投票器进行,我们这里配置了RoleVoter来进行投票:36. public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) {37. int result = ACCESS_ABSTAIN;38. //这里取得资源的安全配置39. Iterator iter = config.getConfigAttributes();40.41. while (iter.hasNext()) {42. ConfigAttribute attribute = (ConfigAttribute) iter.next();43.44. if (this.supports(attribute)) {45. result = ACCESS_DENIED;46.47. // 这里对资源配置的安全授权级别进行判断,也就是匹配ROLE为前缀的角色配置48. // 遍历每个配置属性,如果其中一个匹配该主体持有的GrantedAuthority,则访问被允许。
Spring源码分析基本介绍

Spring源码分析基本介绍摘要:本⽂结合《Spring源码深度解析》来分析Spring 5.0.6版本的源代码。
若有描述错误之处,欢迎指正。
前⾔作为⼀名开发⼈员,阅读源码是⼀个很好的学习⽅式。
本⽂将结合《Spring源码深度解析》来分析Spring 5.0.6版本的源代码,若有描述错误之处,欢迎指正。
Spring是2003年兴起的⼀个轻量级Java开源框架,旨在解决企业应⽤开发的复杂性。
Spring发展⾄今,衍⽣出⾮常丰富的模块,并应⽤在多种场景,⽐如:桌⾯应⽤,Web应⽤等。
Spring的模块化可以允许你只使⽤需要的模块,⽽不必全部引⼊。
⽬录⼀、整体架构1. 核⼼容器2. 数据访问/集成3. Web4. AOP5. Test⼆、设计理念三、使⽤场景1. 典型的Spring web应⽤程序2. Spring中间层使⽤第三⽅web框架3. 远程调⽤4. EJBs-包装现存POJOs⼀、整体架构Spring框架是⼀个分层架构,他包含⼀系列的功能要素,并被分为⼤约20个模块,如下图所⽰(很遗憾,并没有找到Spring5的架构图,下图是Spring4的,但结合Spring5的源码来看,该图还是能够体现Spring5的核⼼模块)这些模块被总结为以下⼏部分。
1. 核⼼容器Core Container(核⼼容器)包含有Core、Beans、Context和Expression Language模块。
Core和Beans模块是框架的基础部分,提供IoC(控制反转)和DI(依赖注⼊)特性。
这⾥的基础概念是BeanFactory,它提供对Factory模式的经典实现来消除对程序性单例模式的需要,并真正地允许你从程序逻辑中分离出依赖关系和配置。
Core模块主要包含Spring框架基本的核⼼⼯具类,Spring的其他组件都要使⽤到这个包⾥的类,Core模块是其他组件的基本核⼼。
当然你也可以在⾃⼰的应⽤系统中使⽤这些⼯具类。
SpringResource源码分析

SpringResource源码分析基本信息Spring为了⽅便程序调⽤不同类型的资源⽽定义的接⼝。
Spring提供若⼲实现,⽅便我们针对不同的资源获取资源⽂件以及对具体内容的操作。
常⽤的有以下三种:1. 通过 FileSystemResource 以⽂件系统绝对路径的⽅式进⾏访问;2. 通过 ClassPathResource 以类路径的⽅式进⾏访问;3. 通过 ServletContextResource 以相对于Web应⽤根⽬录的⽅式进⾏访问。
如下图为基本的类关系图,我们可以看到Resource的主要继承接⼝,以及对应的三⼤主类的实现。
接⼝代码以及逻辑关系1, InputStreamSource该接⼝提供最为资源读取流的简单接⼝。
只有⼀个⽅法:InputStream getInputStream()throwsIOException;该⽅法每次调⽤都会返回⼀个新的流对象。
2,Resource接⼝。
定义了⼀组对底层资源操作的基本⽅法。
boolean exists();boolean isReadable();boolean isOpen();URL getURL()throwsIOException;URI getURI()throwsIOException;File getFile()throwsIOException;long contentLength()throwsIOException;long lastModified()throwsIOException;Resource createRelative(String relativePath)throwsIOException;String getFilename();String getDescription();3,WritableResource:该接⼝提供可供写⼊的资源。
该接⼝继承⾃Resource,并提供⾃⾝的两个写⼊⽅法:boolean isWritable();OutputStream getOutputStream()throwsIOException;4, ContextResource:通过上下⽂获取Resource,例如:javax.servlet.ServletContext。
Spring系列(三):SpringIoC源码解析

Spring系列(三):SpringIoC源码解析⼀、Spring容器类继承图⼆、容器前期准备 IoC源码解析⼊⼝:/*** @desc: ioc原理解析启动* @author: toby* @date: 2019/7/22 22:20*/public class PrincipleMain {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(PrincipleConfig.class);}} 调⽤构造函数AnnotationConfigApplicationContext 调⽤this(),会默认先调⽤⽗类的⽆参构造函数,为ApplicationContext上下⽂对象初始beanFactory = new DefaultListableBeanFactory() 在调⽤当前类的this(),也就是调⽤⾃⼰的⽆参构造函数: 进到创建注解模式下的Bean定义读取器: org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, ng.Object) 主要是注册Spring⾃⾝的⼀些后置处理器public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) {DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);if (beanFactory != null) {if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);}if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());}}Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);/*** 为我们容器中注册解析主配置类的后置处理器ConfigurationClassPostProcessor* beanName = org.springframework.context.annotation.internalConfigurationAnnotationProcessor*/if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));}/*** 为我们容器中注册处理@Autowired注解的Bean的后置处理器AutowiredAnnotationBeanPostProcessor* beanName = org.springframework.context.annotation.internalAutowiredAnnotationProcessor*/if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));}/*** 为我们容器中注册处理@Required属性注解的Bean后置处理器RequiredAnnotationBeanPostProcessor* beanName = org.springframework.context.annotation.internalRequiredAnnotationProcessor*/if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));}/*** 为我们容器注册处理JSR规范注解的Bean后置处理器CommonAnnotationBeanPostProcessor* beanName = org.springframework.context.annotation.internalCommonAnnotationProcessor*/if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));}/*** 为我们容器注册处理jpa的Bean的后置处理器org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor*/if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition();try {def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,AnnotationConfigUtils.class.getClassLoader()));}catch (ClassNotFoundException ex) {throw new IllegalStateException("Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));}/*** 处理监听⽅法的注解解析器EventListenerMethodProcessor*/if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));}/*** 注册事件监听器⼯⼚*/if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));}return beanDefs;} 读取器初始化完成后,Spring的容器的Bean的定义信息就有Spring⾃⾝的⼀些后置处理器了,Debug如下: 读取器初始化完成后,接下来初始化ClassPath下的Bean定义扫描器:org.springframework.context.annotation.ClassPathBeanDefinitionScanner#ClassPathBeanDefinitionScanner(org.springframework.beans.factory.support.BeanDefinitionRegistry, boolean, org.springframework.core.env.Environment, org.springframework.core.io.ResourceLoader) 类路径下的Bean定义扫描 org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#registerDefaultFilters 注⼊默认的Filterprotected void registerDefaultFilters() {this.includeFilters.add(new AnnotationTypeFilter(Component.class));ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");}catch (ClassNotFoundException ex) {// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.}try {this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("d", cl)), false));logger.debug("JSR-330 'd' annotation found and supported for component scanning");}catch (ClassNotFoundException ex) {// JSR-330 API not available - simply skip.}} 这⾥需要注意的是为什么new AnnotationTypeFilter(Component.class)就可以处理@Repository,@Service,@Controller这3个注解,原因如下: ⾃此前期准备⼯作完成三、org.springframework.context.support.AbstractApplicationContext#refresh 12⼤步public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {//1:准备刷新上下⽂环境prepareRefresh();//2:获取初始化Bean⼯⼚ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();//3:对bean⼯⼚进⾏填充属性prepareBeanFactory(beanFactory);try {//4:Spring开放接⼝留给⼦类去实现该接⼝postProcessBeanFactory(beanFactory);//5:调⽤我们的bean⼯⼚的后置处理器invokeBeanFactoryPostProcessors(beanFactory);//6:注册我们bean后置处理器registerBeanPostProcessors(beanFactory);//7:初始化国际化资源处理器initMessageSource();//8:初始化事件多播器initApplicationEventMulticaster();//9:这个⽅法同样也是留个⼦类实现,其中springboot也是从这个⽅法进⾏tomcat的启动onRefresh();//10:把我们的事件监听器注册到多播器上registerListeners();//11:实例化所有的⾮懒加载的单实例beanfinishBeanFactoryInitialization(beanFactory);//12:最后刷新容器发布刷新事件(Spring cloud eureka也是从这⾥启动的)finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}} 第⼀步:prepareRefresh() 准备刷新上下⽂环境:protected void prepareRefresh() {// Switch to active.this.startupDate = System.currentTimeMillis();this.closed.set(false);this.active.set(true);if (logger.isInfoEnabled()) {("Refreshing " + this);}/*** 初始化上下⽂环境*/initPropertySources();/*** ⽤来校验我们容器启动必须依赖的环境变量的值*/getEnvironment().validateRequiredProperties();/*** 创建⼀个早期事件监听器对象*/if (this.earlyApplicationListeners == null) {this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);}else {// Reset local application listeners to pre-refresh state.this.applicationListeners.clear();this.applicationListeners.addAll(this.earlyApplicationListeners);}/*** 创建⼀个容器⽤于保存早期待发布的事件集合什么是早期事件了?* 就是我们的事件监听器还没有注册到事件多播器上的时候都称为早期事件*/this.earlyApplicationEvents = new LinkedHashSet<>();} 第⼆步:ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory() 获取初始化的Bean的⼯⼚:protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {//刷新bean⼯⼚()refreshBeanFactory();//返回之前容器准备⼯作的时候创建的的bean⼯⼚也就是DefaultListableBeanFactory(很重要)ConfigurableListableBeanFactory beanFactory = getBeanFactory();if (logger.isDebugEnabled()) {logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);}return beanFactory;} org.springframework.context.support.GenericApplicationContext#refreshBeanFactory,注意只能刷⼀次protected final void refreshBeanFactory() throws IllegalStateException {//由于BeanFactory只能刷新⼀次,多线程情况下可能导致线程安全问题,所有使⽤cas原⼦操作来保证if (!pareAndSet(false, true)) {throw new IllegalStateException("GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");}//指定Bean⼯⼚的序列化Idthis.beanFactory.setSerializationId(getId());} 第三步:prepareBeanFactory(beanFactory) 对bean⼯⼚进⾏填充属性:protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {//设置bean⼯⼚的类加载器为当前application应⽤上下⽂的加载器beanFactory.setBeanClassLoader(getClassLoader());//为bean⼯⼚设置SPEL表达式解析器对象StandardBeanExpressionResolverbeanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));//为我们的bean⼯⼚设置了⼀个propertyEditor属性资源编辑器对象(⽤于后⾯的给bean对象赋值使⽤)beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));//注册ApplicationContextAwareProcessor后置处理器⽤来处理ApplicationContextAware接⼝的回调⽅法beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));/*** 当Spring将ApplicationContextAwareProcessor注册后,那么在invokeAwarelnterfaces⽅法中调⽤的Aware类已经不是普通的bean了,* 如ResourceLoaderAware、ApplicationEventPublisherAware、ApplicationContextAware等,那么当然需要在Spring做bean的依赖注⼊的时候忽略它们。
Spring源码解析-beanfactory

Spring源码解析-beanfactory Demopublic class MyBeanTest {public static void main(String[] args) {BeanFactory ctx = new XmlBeanFactory(new ClassPathResource("spring.xml"));MyBean testBean = (MyBean)ctx.getBean("testBean");System.out.println(testBean.getTestStr());}}package qbb.spring.bean;public class MyBean {private String testStr = "testStr";public MyBean(){}public MyBean(String testStr){this.testStr = testStr;}public String getTestStr() {return testStr;}public void setTestStr(String testStr) {this.testStr = testStr;}}<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/context"xsi:schemaLocation="/schema/beans<bean name="testBean" class="qbb.spring.bean.MyBean" ></bean></beans>uml类图上次看的时候就画过这个图,这次做了细化和调整。
Spring源码剖析9:Spring事务源码剖析

Spring源码剖析9:Spring事务源码剖析本系列⽂章将整理到我在GitHub上的《Java⾯试指南》仓库,更多精彩内容请到我的仓库⾥查看喜欢的话⿇烦点下Star哈⽂章将同步到我的个⼈博客:本⽂是微信公众号【Java技术江湖】的《Spring和SpringMVC源码分析》其中⼀篇,本⽂部分内容来源于⽹络,为了把本⽂主题讲得清晰透彻,也整合了很多我认为不错的技术博客内容,引⽤其中了⼀些⽐较好的博客⽂章,如有侵权,请联系作者。
该系列博⽂会告诉你如何从spring基础⼊⼿,⼀步步地学习spring基础和springmvc的框架知识,并上⼿进⾏项⽬实战,spring框架是每⼀个Java⼯程师必须要学习和理解的知识点,进⼀步来说,你还需要掌握spring甚⾄是springmvc的源码以及实现原理,才能更完整地了解整个spring技术体系,形成⾃⼰的知识框架。
后续还会有springboot和springcloud的技术专题,陆续为⼤家带来,敬请期待。
为了更好地总结和检验你的学习成果,本系列⽂章也会提供部分知识点对应的⾯试题以及参考答案。
如果对本系列⽂章有什么建议,或者是有什么疑问的话,也可以关注公众号【Java技术江湖】联系作者,欢迎你参与本系列博⽂的创作和修订。
声明式事务使⽤Spring事务是我们⽇常⼯作中经常使⽤的⼀项技术,Spring提供了编程、注解、aop切⾯三种⽅式供我们使⽤Spring事务,其中编程式事务因为对代码⼊侵较⼤所以不被推荐使⽤,注解和aop切⾯的⽅式可以基于需求⾃⾏选择,我们以注解的⽅式为例来分析Spring事务的原理和源码实现。
⾸先我们简单看⼀下Spring事务的使⽤⽅式,配置:<tx:annotation-driven transaction-manager="transactionManager"/><bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean>在需要开启事务的⽅法上加上@Transactional注解即可,这⾥需要注意的是,当标签在不指定transaction-manager属性的时候,会默认寻找id固定名为transactionManager的bean作为事务管理器,如果没有id为transactionManager的bean并且在使⽤@Transactional注解时也没有指定value(事务管理器),程序就会报错。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第 2 / 90 页
1.1 Spring源代码解析(一):IOC容器
1.1 Spring源代码解析(一):IOC容器
发表时间: 2007-06-03 在认真学习Rod.Johnson的三部曲之一:<<Professional Java Development with the spring framework>>,顺便也看了看源代码想知道个 究竟,抛砖引玉,有兴趣的同志一起讨论研究吧! 以下内容引自博客:/,欢迎指导:) 在Spring中,IOC容器的重要地位我们就不多说了,对于Spring的使用者而言,IOC容器实际上是什么呢?我们可以说BeanFactory就是 我们看到的IoC容器,当然了Spring为我们准备了许多种IoC容器来使用,这样可以方便我们从不同的层面,不同的资源位置,不同的形 式的定义信息来建立我们需要的IoC容器。 在Spring中,最基本的IOC容器接口是BeanFactory - 这个接口为具体的IOC容器的实现作了最基本的功能规定 - 不管怎么着,作为IOC容 器,这些接口你必须要满足应用程序的最基本要求:
我们在后面会看到读取器读取资源和注册bean定义信息的整个过程,基本上是和上下文的处理是一样的,从这里我们可以看到上下文 和 XmlBeanFactory这两种IOC容器的区别,BeanFactory往往不具备对资源定义的能力,而上下文可以自己完成资源定义,从这个角度 上看上下文更好用一些。 仔细分析Spring BeanFactory的结构,我们来看看在BeanFactory基础上扩展出的ApplicationContext - 我们最常使用的上下文。除了具备 BeanFactory的全部能力,上下文为应用程序又增添了许多便利: * 可以支持不同的信息源,我们看到ApplicationContext扩展了MessageSource * 访问资源 , 体现在对ResourceLoader和Resource的支持上面,这样我们可以从不同地方得到bean定义资源 * 支持应用事件,继承了接口ApplicationEventPublisher,这样在上下文中引入了事件机制而BeanFactory是没有的。 ApplicationContext允许上下文嵌套 - 通过保持父上下文可以维持一个上下文体系 - 这个体系我们在以后对Web容器中的上下文环境的
第 4 / 90 页
1.1 Spring源代码解析(一):IOC容器
分析中可以清楚地看到。对于bean的查找可以在这个上下文体系中发生,首先检查当前上下文,其次是父上下文,逐级向上,这样为 不同的Spring应用提供了一个共享的bean定义环境。这个我们在分析Web容器中的上下文环境时也能看到。 ApplicationContext提供IoC容器的主要接口,在其体系中有许多抽象子类比如AbstractApplicationContext为具体的BeanFactory的实现, 比如FileSystemXmlApplicationContext和 ClassPathXmlApplicationContext提供上下文的模板,使得他们只需要关心具体的资源定位问 题。当应用程序代码实例化 FileSystemXmlApplicationContext的时候,得到IoC容器的一种具体表现 - ApplicationContext,从而应用程 序通过ApplicationContext来管理对bean的操作。 BeanFactory 是一个接口,在实际应用中我们一般使用ApplicationContext来使用IOC容器,它们也是IOC容器展现给应用开发者的使用 接口。对应用程序开发者来说,可以认为BeanFactory和ApplicationFactory在不同的使用层面上代表了SPRING提供的IOC容器服务。 下面我们具体看看通过FileSystemXmlApplicationContext是怎样建立起IOC容器的, 显而易见我们可以通过new来得到IoC容器:
目录
1. 默认类别
1.1 Spring源代码解析(一):IOC容器 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.2 Spring源代码解析(二):IoC容器在Web容器中的启动 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 1.3 Spring源代码解析(三):Spring JDBC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 1.4 Spring源代码解析(四):Spring MVC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 1.5 Spring源代码解析(五):Spring AOP获取Proxy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 1.6 Spring源代码解析(六):Spring声明式事务处理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 1.7 Spring源代码解析(七):Spring AOP中对拦截器调用的实现 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 1.8 Spring源代码解析(八):Spring驱动Hibernate的实现 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 1.9 Spring源代码解析(九):Spring Acegi框架鉴权的实现 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 1.10 Spring源代码解析(十):Spring Acegi框架授权的实现 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
第 3 / 90 页
1.1 Spring源代码解析(一):IOC容器
准备好了一系列工厂来让我们使用。比如XmlBeanFactory就是针对最基础的BeanFactory的IOC容器的实现 - 这个实现使用xml来定义IOC 容器中的bean。 Spring提供了一个BeanFactory的基本实现,XmlBeanFactory同样的通过使用模板模式来得到对IOC容器的抽象AbstractBeanFactory,DefaultListableBeanFactory这些抽象类为其提供模板服务。其中通过resource 接口来抽象bean定义数据,对Xml 定义文件的解析通过委托给XmlBeanDefinitionReader来完成。下面我们根据书上的例子,简单的演示IOC容器的创建过程:
- 做最棒的软件开发交流社区
jiwenke的博客文章 - Spring源代码 解析
作者: jiwenke
我的博客文章精选 பைடு நூலகம்Spring源代码解析
第 1 / 90 页
本书由JavaEye提供的电子书DIY功能自动生成于 2008-11-19
//这里根据bean名字得到bean实例,并同时判断这个bean是不是单件 boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
//这里对得到bean实例的Class类型 Class getType(String name) throws NoSuchBeanDefinitionException;
//这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来 String[] getAliases(String name);
}
在BeanFactory里只对IOC容器的基本行为作了定义,根本不关心你的bean是怎样定义怎样加载的 - 就像我们只关心从这个工厂里我们 得到到什么产品对象,至于工厂是怎么生产这些对象的,这个基本的接口不关心这些。如果要关心工厂是怎样产生对象的,应用程序 需要使用具体的IOC容器实现- 当然你可以自己根据这个BeanFactory来实现自己的IOC容器,但这个没有必要,因为Spring已经为我们
//这里根据bean的名字和Class类型来得到bean实例,和上面的方法不同在于它会抛出异常:如果根据名字取得的bean实例的Class类型和需要的 Object getBean(String name, Class requiredType) throws BeansException;
//这里提供对bean的检索,看看是否在IOC容器有这个名字的bean boolean containsBean(String name);