自我成长 - 开源框架
type: channel
link: https://yanxizhu.com/index.php/category/framework/
description: 框架学习
items: SpringBoot源码解析(四)：监听器
items: SpringBoot源码解析(三)：SpringBoot内嵌Tomcat
items: Spring的自动配置原理
items: SpringBoot运行原理
items: SpringBoot源码(二)：自动装配原理
items: SpringBoot源码解析(一):启动过程
items: Springboot同一Server类方法调用事务解决方案
items: Springboot拦截器配置
items: Shiro权限管理框架

SpringBoot源码解析(四)：监听器
type: item
date: 2022-04-26T13:52:44+00:00
description: springboot源码解析(四)：监听器​ 在看springboot的源码过程中，发现内部使用了大量的监听器，下面来看下监听器的作用。在springboot的监听器有如下两类：# Run Listeners #事件发布运行监听器，是springboot中配置的唯一一个应用运行监听器，作用是通过一个多路广播器，将springboot运行状态的变化，构建成事件，并广播给各个监听器 org.springframework.boot.SpringApplicationRunListener=\ org.springframework.boot.context.event.EventPublishingRunListener # Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.ClearCachesApplicationListener(),\ org.springframework.boot.builder.ParentContextCloserApplicationListener,\ org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\ org.springframework.boot.context.FileEncodingApplicationListener,\ org.springframework.boot.context.config.AnsiOutputApplicationListener,\ org.springframework.boot.context.config.ConfigFileApplicationListener,\ org.springframework.boot.context.config.DelegatingApplicationListener,\ org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\ org.springframework.boot.context.logging.LoggingApplicationListener,\ org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener # Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.autoconfigure.BackgroundPreinitializer​ 当程序开始运行的时候，可以看到启动了一个运行时监听器，并且创建了一个SpringApplicationRunListeners对象，该对象是一个封装工具类，封装了所有的启动监听器：代码如下class SpringApplicationRunListeners { private final Log log; //启动类监听器 private final List<SpringApplicationRunListener> listeners; SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) { this.log = log; this.listeners = new ArrayList<>(listeners); } //启动上下文事件监听 void starting() { for (SpringApplicationRunListener listener : this.listeners) { listener.starting(); } } //environment准备完毕事件监听 void environmentPrepared(ConfigurableEnvironment environment) { for (SpringApplicationRunListener listener : this.listeners) { listener.environmentPrepared(environment); } } //spring上下文准备完毕事件监听 void contextPrepared(Configurabl…

SpringBoot源码解析(三)：SpringBoot内嵌Tomcat
type: item
date: 2022-04-26T13:50:00+00:00
description: springboot源码解析(三)：springboot内嵌tomcat​ 在使用springboot搭建一个web应用程序的时候，我们发现不需要自己搭建一个tomcat服务器，只需要引入spring-boot-starter-web,在应用启动时会自动启动嵌入式的tomcat作为服务器，下面来分析下源码的分析流程： ​ 之前我们已经讲过了自动装配的原理，其实tomcat的实现机制也是从自动装配开始的。1、ServletWebServerFactoryAutoConfiguration类@Configuration(proxyBeanMethods = false) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @ConditionalOnClass(ServletRequest.class) @ConditionalOnWebApplication(type = Type.SERVLET) @EnableConfigurationProperties(ServerProperties.class) @Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, ServletWebServerFactoryConfiguration.EmbeddedTomcat.class, ServletWebServerFactoryConfiguration.EmbeddedJetty.class, ServletWebServerFactoryConfiguration.EmbeddedUndertow.class }) public class ServletWebServerFactoryAutoConfiguration { @Bean public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) { return new ServletWebServerFactoryCustomizer(serverProperties); } @Bean @ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat") public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer( ServerProperties serverProperties) { return new TomcatServletWebServerFactoryCustomizer(serverProperties); } @Bean @ConditionalOnMissingFilterBean(ForwardedHeaderFilter.class) @ConditionalOnProperty(value = "server.forward-headers-strategy", havingValue = "framework") public FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter() { ForwardedHeaderFilter filter = new ForwardedHeaderFilter(); FilterRegistrationBean<ForwardedHeaderFilter> registration = new FilterRegistrationBean<>(filter); registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR); registration.setOrder(Ordered.HIGHEST_PRECEDENCE); return registration; } /** * Registers a {@link WebServerFactoryCustomizerBeanPostProcessor}. Registered via * {@link ImportBeanDefinitionRegistrar} for early registration. */ public static clas…

Spring的自动配置原理
type: item
date: 2022-04-26T13:48:00+00:00
description: spring的自动配置原理springboot配置文件的装配过程1、springboot在启动的时候会加载主配置类，开启了@EnableAutoConfiguration。2、@EnableAutoConfiguration的作用：利用AutoConfigurationImportSelector给容器导入一些组件。查看selectImports方法的内容，返回一个AutoConfigurationEntryAutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata); ------ List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); ------ protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; }可以看到SpringFactoriesLoader.loadFactoryNames，继续看又调用了loadSpringFactories方法，获取META-INF/spring.factories资源文件public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) { String factoryTypeName = factoryType.getName(); return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList()); } private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { MultiValueMap<String, String> result = cache.get(classLoader); if (result != null) { return result; } try { Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); for (Map.Entry<?, ?> entry : properties.entrySet()) { String factoryTypeName = ((String) entry.getKey()).trim(); for (String factoryImplementationName : StringUtils.commaDelimitedLi…

SpringBoot运行原理
type: item
date: 2022-04-26T13:47:15+00:00
description: springboot运行原理1、启动器<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>​ springboot-boot-starter:就是springboot的场景启动器。springboot将所有的功能场景都抽取出来，做成一个个的starter，只需要在项目中引入这些starter即可，所有相关的依赖都会导入进来，根据公司业务需求决定导入什么启动器即可。2、主程序package com.mashibing; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; //SpringBootApplication注解用来标注一个主程序类，说明是一个springboot应用 @SpringBootApplication public class StudyApplication { public static void main(String[] args) { SpringApplication.run(StudyApplication.class, args); } }查看@SpringBootApplication/* @ComponentScan:自动扫描并加载符合条件的组件或者bean，将这个bean定义加载到IOC容器中 @SpringBootConfiguration:标注在某个类上，表示这是一个springboot的配置类。 @EnableAutoConfiguration:开启自动配置功能,之前在使用springboot的时候，springboot可以自动帮我们完成配置功能，@EnableAutoConfiguration告诉springboot开启自动配置功能，这样自动配置才能生效 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication {}/* 可以看到SpringBootConfiguration使用了Configuration注解来标注 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration public @interface SpringBootConfiguration {}/* 可以看到Configuration也是容器中的一个组件 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Configuration {}/* @AutoConfigurationPackage:自动配置包 @Import(AutoConfigurationImportSelector.class)：导入哪些组件的选择器，它将所有需要导入的组件以全类名的方式返回，这些组件就会被添加到容器中，它会给容器中导入非常多的自动配置类，就是给容器中导入这个场景需要的所有组件，并配置好这些组件 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {}/* 给容器导入一个…

SpringBoot源码(二)：自动装配原理
type: item
date: 2022-04-26T13:45:54+00:00
description: springboot源码(二)：自动装配原理​ 在之前的课程中我们讲解了springboot的启动过程，其实在面试过程中问的最多的可能是自动装配的原理，而自动装配是在启动过程中完成，只不过在刚开始的时候我们选择性的跳过了，下面详细讲解自动装配的过程。1、在springboot的启动过程中，有一个步骤是创建上下文，如果不记得可以看下面的代码：public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); //此处完成自动装配的过程 prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }2、在prepareContext方法中查找load方法，一层一层向内点击，找到最终的load方法//prepareContext方法 private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { context.setEnvironment(environment); postProcessApplic…

SpringBoot源码解析(一):启动过程
type: item
date: 2022-04-26T13:40:00+00:00
description: springboot源码解析(一):启动过程1、springboot的入口程序@SpringBootApplication public class StartupApplication { public static void main(String[] args) { SpringApplication.run(StartupApplication.class, args); } }当程序开始执行之后，会调用SpringApplication的构造方法，进行某些初始参数的设置//创建一个新的实例，这个应用程序的上下文将要从指定的来源加载Bean public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { //资源初始化资源加载器，默认为null this.resourceLoader = resourceLoader; //断言主要加载资源类不能为 null，否则报错 Assert.notNull(primarySources, "PrimarySources must not be null"); //初始化主要加载资源类集合并去重 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); //推断当前 WEB 应用类型，一共有三种：NONE,SERVLET,REACTIVE this.webApplicationType = WebApplicationType.deduceFromClasspath(); //设置应用上线文初始化器,从"META-INF/spring.factories"读取ApplicationContextInitializer类的实例名称集合并去重，并进行set去重。（一共7个） setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); //设置监听器,从"META-INF/spring.factories"读取ApplicationListener类的实例名称集合并去重，并进行set去重。（一共11个） setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); //推断主入口应用类，通过当前调用栈，获取Main方法所在类，并赋值给mainApplicationClass this.mainApplicationClass = deduceMainApplicationClass(); }在上述构造方法中，有一个判断应用类型的方法，用来判断当前应用程序的类型： static WebApplicationType deduceFromClasspath() { if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { return WebApplicationType.REACTIVE; } for (String className : SERVLET_INDICATOR_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return WebApplicationType.NONE; } } return WebApplicationType.SERVLET; } //WebApplicationType的类型 public enum WebApplicationType { /** * The application should not run as a web application and should not start an * embedded web server. * 非web项目 */ NONE, /** * The application should run as a servlet-based web application and should start an * embedded servlet web server. * servlet web 项目 */ SERVLET, /** * …

Springboot同一Server类方法调用事务解决方案
type: item
date: 2022-03-12T05:24:00+00:00
description: Springboot同一Server类方法调用事务解决方案1、引入springboot-aop start<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>主要是使用里面的动态代理 <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.7</version> <scope>compile</scope> </dependency>2、开启动态代理@EnableAspectJAutoProxy(exposeProxy = true) @EnableDiscoveryClient @SpringBootApplication public class FamilyBookingApplication { public static void main(String[] args) { SpringApplication.run(FamilyBookingApplication.class, args); } }@EnableAspectJAutoProxy(exposeProxy = true)：开启aspectj动态代理功能。以后所有的动态代理都是aspectj对象暴露代理对象。3、本类互调用代理对象调用@Service("userService") public class UserServiceImpl implements userService { @Transactional public void a(){ UserService userService = (UserService)AopContext.currentProxy(); userService.b(); userService.c(); } @Transactional public void b(){ } @Transactional public void c(){ } }

Springboot拦截器配置
type: item
date: 2022-03-10T14:47:00+00:00
description: Springboot拦截器配置1、拦截器配置，主要实现HandlerInterceptor接口import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @description: 拦截器，配合FamilyWebConfig 配置使用 * @author: 清风 * @date: 2022/3/10 22:36 * @version: 1.0 */ @Component public class LoginUserInterceptor implements HandlerInterceptor { public static ThreadLocal<Object> objUser = new ThreadLocal<>(); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object loginusr = request.getSession().getAttribute("LOGIN_USR"); if(loginusr != null){ objUser.set(loginusr); //登录了才能访问 return true; }else{ //没登录，跳转去登录 return false; } } } 由于拦截器需要配合web配置使用，因此创建web配置。2、web配置主要实现WebMvcConfigurer接口import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * @description: WEB配置 * @author: 清风 * @date: 2022/3/10 22:40 * @version: 1.0 */ public class FamilyWebConfig implements WebMvcConfigurer { @Autowired LoginUserInterceptor loginUserInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginUserInterceptor).addPathPatterns("/**"); } }

Shiro权限管理框架
type: item
date: 2022-02-28T12:59:36+00:00
description: 首先知道Shiro架构有3个主要概念：Subject、SecurityManager和Realms。 Shiro基础架构图 ： 基础架构说明：Subject: As we’ve mentioned in our Tutorial, the Subject is essentially a security specific ‘view’ of the the currently executing user. Whereas the word ‘User’ often implies a human being, a Subject can be a person, but it could also represent a 3rd-party service, daemon account, cron job, or anything similar - basically anything that is currently interacting with the software.Subject instances are all bound to (and require) a SecurityManager. When you interact with a Subject, those interactions translate to subject-specific interactions with the SecurityManager.（大概意思：Subject一词是一个安全术语，其基本意思是“当前的操作用户”。称之为“用户”并不准确，因为“用户”一词通常跟人相关。在安全领域，术语“Subject”可以是人，也可以是第三方进程、后台帐户（Daemon Account）、定时作业（Corn Job）或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。但考虑到大多数目的和用途，你可以把它认为是Shiro的“用户”概念。在程序中你都能轻易的获得Subject，允许在任何需要的地方进行安全操作。每个Subject对象都必须与一个SecurityManager进行绑定，你访问Subject对象其实都是在与SecurityManager里的特定Subject进行交互。）SecurityManager: The SecurityManager is the heart of Shiro’s architecture and acts as a sort of ’umbrella’ object that coordinates its internal security components that together form an object graph. However, once the SecurityManager and its internal object graph is configured for an application, it is usually left alone and application developers spend almost all of their time with the Subject API.We will talk about the SecurityManager in detail later on, but it is important to realize that when you interact with a Subject, it is really the SecurityManager behind the scenes that does all the heavy lifting for any Subject security operation. This is reflected in the basic flow diagram above.(大概意思：Subject的“幕后”推手是SecurityManager。Subject代表了当前用户的安全操作，SecurityManager则管理所有用户的安全操作。它是Shiro框架的核心，充当“保护伞”，引用了多个内部嵌套安全组件，它们形成了对象图。但是，一旦SecurityManager及其内部对象图配置好，它就会退居幕后，应用开发人员几乎把他们的所有时间都花在Subject API调用上。那么，如何设置SecurityManager呢？嗯，这要看应用的环境。例如，Web应用通常会在Web.xml中指定一个Shiro Servlet Filter，这会创建SecurityManager实例，如果你运行的是一个独立应用，你需要用其他配置方式，但有很多配置选项。一个应用…