首页 文章 精选 留言 我的

精选列表

搜索[HTTP/2],共10000篇文章
优秀的个人博客,低调大师

快速上手物联网解决方案(2)—— 云平台

常见的物联网解决方案包括了设备端、上云、应用端三大部分,本实例以内置 AliOS Things 的 Developerkit 开发板 (购买地址)为设备端,通过上传板载加速度计三轴坐标值至云端,将数据转储到表格存储,并最终通过可视化折线图展示。 本实例使用的阿里云产品有:物联网平台、表格存储、DataV 数据可视化。 阿里云物联网平台提供安全可靠的设备连接通信能力帮助用户将海量设备数据采集上云,平台提供功能丰富的设备管理能力帮助用户远程维护设备,平台提供丰富的API以及与阿里云众多云产品打通的规则引擎,帮助用户将应用快速集成。 下面我们开始平台的相关操作指导: 1. 注册阿里云账号 阿里云物联网平台依托阿里云,使用前需要先注册阿里云账号:https://account.aliyun.com/register/register.htm 并通过

优秀的个人博客,低调大师

第2章—装配Bean—通过java代码装配bean

通过java代码装配bean ​ 在进行显式装配的时候,有两种选型方案:java和XML配置,这里先介绍java的配置方式. 2.3.1创建配置类 先复习下上一章的配置内容: @Configuration public class SgtPeppers implements CompactDisc { private String title = "sgt"; private String song = "Twinkle, twinkle, little start"; public void play() { System.out.println("title:" + title + "song:" + song); } } ​ 这里我们移走了@ComponentScan的注解,只留下了@Configuration的注解,表明这个类是一个配置类,不包含如何实现bean的细节,如果单纯的这样运行的话,测试会失败并出现BeanCreation-Exception异常.测试期望被注入CDPlayer和CompactDisc,但是这些bean根本就没有创建,因为组件扫描不会发现他们.为了测试通过就需要加回@ComponentScan的注解. 2.3.2.声明简单的bean 我们要在javaConfig中声明bean,需要在方法上加上@Bean的注解,如下: @Bean public CompactDisc sgtPeppers(){ return new SgtPeppers(); } 默认情况下,bean的ID与带有@Bean的注解的方法名是一样的(本例子是sgtPeppers),如果你想设置成一个不同的名字的话,可以重命名为该方法指定bean的Name属性@Bean(name = "otherName")的方式来实现.

优秀的个人博客,低调大师

CC框架实践(2):Fragment和View的组件化

前言 本文将介绍如何在CC框架下实现Fragment和View的组件化。 一、需求背景 在android组件化过程中,你有没有遇到这样的问题: 单Activity + 多Fragment的架构下,如何进行Fragment的组件化? 主界面上的Fragment太多,想用组件化进行管理,该怎么做? 一个功能模块比较独立,但在主界面使用了其中一个Fragment,如何解耦? 对某些View进行了封装或者自定义的View,功能比较独立,是作为基础库通过类依赖使用好还是作为组件使用比较好?如果要作为组件使用,那要如何组件化? 二、现有的一些解决方案: 在主app中依赖所有组件,所以在主app中可直接使用这些组件中的Fragment或View的类 直接使用具体的类将产生耦合,违背了组件化的解耦目的 组件之间的fragment引用也需要直接依赖,这样就变成了一个库而

优秀的个人博客,低调大师

spring boot 源码解析2-SpringApplication初始化

前⾔我们⽣成⼀个spring boot 项⽬时,会⾃带⼀个启动类. 代码如下: @SpringBootApplication public class SpringBootAnalysisApplication { public static void main(String[] args) { SpringApplication.run(SpringBootAnalysisApplication.class, args); } } 就是这么简单的代码,构成了spring boot的世界. 那么代码中只有⼀个@SpringBootApplication 注解 和 调⽤了SpringApplication#run⽅法.那么我们先来解析SpringApplication的run⽅法. 解析⾸先调⽤了org.springframework.boot.SpringApplication#run(Object, String...) ⽅法.代码如下: public static ConfigurableApplicationContext run(Object source, String... args) { return run(new Object[] { source }, args); } 接着调⽤如下代码: public static ConfigurableApplicationContext run(Object[] sources, String[] args) { return new SpringApplication(sources).run(args); } 可以发现 ⾸先初始化了SpringApplication,然后调⽤其实例⽅法:run. 在 SpringApplication 的构造器中,调⽤了 initialize ⽅法. public SpringApplication(Object... sources) { initialize(sources); } SpringApplication#initialize⽅法代码如下: private void initialize(Object[] sources) { if (sources != null && sources.length > 0) { this.sources.addAll(Arrays.asList(sources)); } this.webEnvironment = deduceWebEnvironment(); setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); } 可以看到做了如下5件事: 如果sources⻓度⼤于0的话,加⼊到SpringApplication的sources中,该sources是⼀个LinkedHashSet. 调⽤deduceWebEnvironment⽅法判断是否是web环境 设置initializers. 设置Listeners. 设置mainApplicationClass. deduceWebEnvironment代码如下: private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext" }; private boolean deduceWebEnvironment() { for (String className : WEB_ENVIRONMENT_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return false; } } return true; } 可以发现会调⽤ClassUtils类的isPresent⽅法,检查classpath中是否存在javax.servlet.Servlet类和org.springframework.web.context.ConfigurableWebApplicationContext类,如果存在的话,返回true.否则返回false. 在设置Initializers时⾸先调⽤getSpringFactoriesInstances⽅法加载ApplicationContextInitializer.然后直接赋值给initializers.代码如下: private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) { return getSpringFactoriesInstances(type, new Class<?>[] {}); } 转⽽调⽤如下代码: private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // Use names and ensure unique to protect against duplicates // 使⽤Set保存names来避免重复元素 Set<String> names = new LinkedHashSet<String>( SpringFactoriesLoader.loadFactoryNames(type, classLoader)); // 根据names来进⾏实例化 List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); // 对实例进⾏排序 AnnotationAwareOrderComparator.sort(instances); return instances; } 该⽅法逻辑如下: ⾸先获得ClassLoader. 调⽤SpringFactoriesLoader#loadFactoryNames进⾏加载,然后放⼊到LinkedHashSet进⾏去重. 调⽤createSpringFactoriesInstances进⾏初始化 排序其中SpringFactoriesLoader#loadFactoryNames代码如下: public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); try { Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURC E_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); List<String> result = new ArrayList<String>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url)); String factoryClassNames = properties.getProperty(factoryClassName); result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassN ames))); } return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } } 逻辑如下: 获得factoryClassName,对于当前来说factoryClassName =org.springframework.context.ApplicationContextInitializer. 通过传⼊的classLoader加载META-INF/spring.factories⽂件. 通过调⽤PropertiesLoaderUtils#loadProperties将其转为Properties. 获得factoryClassName对应的值进⾏返回.对于当前来说,由于我们只加⼊了spring-boot-starter-web的依赖,因此会加载如下的配置: 在spring-boot/META-INF/spring.factories中.org.springframework.context.ApplicationContextInitializer值如下: org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\ org.springframework.boot.context.ContextIdApplicationContextInitializer,\ org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\ org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer 在spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories中.org.springframework.context.ApplicationContextInitializer值如下: org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\ org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer 因此会加载6个.SpringApplication#createSpringFactoriesInstances⽅法如下: private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) { List<T> instances = new ArrayList<T>(names.size()); for (String name : names) { try { Class<?> instanceClass = ClassUtils.forName(name, classLoader); Assert.isAssignable(type, instanceClass); Constructor<?> constructor = instanceClass .getDeclaredConstructor(parameterTypes); T instance = (T) BeanUtils.instantiateClass(constructor, args); instances.add(instance); } catch (Throwable ex) { throw new IllegalArgumentException( "Cannot instantiate " + type + " : " + name, ex); } } return instances; } 逻辑如下:遍历传⼊的names,也就是之前通过SpringFactoriesLoader加载的类名.通过遍历,依次调⽤其构造器进⾏初始化.加⼊到instances.然后进⾏返回.对于当前场景来说:ConfigurationWarningsApplicationContextInitializer,DelegatingApplicationContextInitializer,ServerPortInfoApplicationContextInitializer初始化没有做任何事.ContextIdApplicationContextInitializer在初始化时.会获得spring boot的应⽤名.搜索路径如下: spring.application.name vcap.application.name spring.config.name 如果都没有配置的话,返回application.代码如下: private static final String NAME_PATTERN = "${spring.application.name:${vcap.application.name:${s pring.config.name:application}}}"; public ContextIdApplicationContextInitializer() { this(NAME_PATTERN); } public ContextIdApplicationContextInitializer(String name) { this.name = name; } 设置SpringApplication#setListeners时,还是同样的套路.调⽤getSpringFactoriesInstances加载META-INF/spring.factories中配置的org.springframework.context.ApplicationListener. 对于当前来说.加载的类如下: org.springframework.context.ApplicationListener=\ org.springframework.boot.ClearCachesApplicationListener,\ org.springframework.boot.builder.ParentContextCloserApplicationListener,\ 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.liquibase.LiquibaseServiceLocatorApplicationListener,\ org.springframework.boot.logging.ClasspathLoggingApplicationListener,\ org.springframework.boot.logging.LoggingApplicationListener 这些类在构造器中都没有做任何事. 调⽤SpringApplication#deduceMainApplicationClass⽅法.获得应⽤的启动类.该⽅法通过获取当前⽅法调⽤栈,找到main函数的类.代码如下: private Class<?> deduceMainApplicationClass() { try { StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); for (StackTraceElement stackTraceElement : stackTrace) { if ("main".equals(stackTraceElement.getMethodName())) { return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) { // Swallow and continue } return null; } 流程图如下: 参考内容:Spring Boot源码解析

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册