首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >@ConfigurationProperties工作原理

@ConfigurationProperties工作原理

作者头像
叔牙
发布于 2023-09-07 01:39:52
发布于 2023-09-07 01:39:52
55200
代码可运行
举报
运行总次数:0
代码可运行

一、使用方式

@ConfigurationProperties是springboot框架中一个比较重要的注解,和@EnableConfigurationProperties一起使用,用于将配置属性绑定到Java类的字段上。这样可以方便地在应用程序中读取和使用配置属性。

1.定义属性配置

在应用配置文件中定义需要绑定的相关属性。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
alarm:
  openAlarm: true
  alarmType: 1
  webhookUrl: https://open.feishu.cn/open-apis/bot/v2/hook/xxxx
2.定义对应属性配置类

定义接收属性解析后需要绑定属性的目标类。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Data
@ConfigurationProperties(prefix = "alarm")
public class AlarmConfig {


    private Boolean openAlarm;


    private Integer alarmType;


    private String webhookUrl;
}
3.定义自动配置类

在自定义配置类或者自动装配类上添加@EnableConfigurationProperties注解并填入属性配置类。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Configuration
@EnableConfigurationProperties({AlarmConfig.class})
@Slf4j
public class AlarmAutoConfiguration {
  //声明配置和bean信息
}
4.使用属性配置

在业务类中通过@Resource或者@Autowired方式注入属性配置类,就可以像其他bean一样使用属性配置了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Service
@Slf4j
public class CustomService {
    @Autowired
    AlarmConfig alarmConfig;
    
    public void doSomething() {
      log.info("read props;config={}",this.alarmConfig);  
    }
}

二、原理介绍

@ConfigurationProperties属性绑定能力的开启是@EnableConfigurationProperties注解,我们就从@EnableConfigurationProperties注解开始分析属性绑定的工作原理。

1.@EnableConfigurationProperties注解

先看一下注解的定义:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EnableConfigurationPropertiesRegistrar.class)
public @interface EnableConfigurationProperties {


String VALIDATOR_BEAN_NAME = "configurationPropertiesValidator";


Class<?>[] value() default {};


}

注解只有一个属性,是需要进行属性绑定的类数组,并且该注解导入了EnableConfigurationPropertiesRegistrar类,该类是属性绑定能力实现的关键。

2.EnableConfigurationPropertiesRegistrar
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class EnableConfigurationPropertiesRegistrar implements ImportBeanDefinitionRegistrar {


private static final String METHOD_VALIDATION_EXCLUDE_FILTER_BEAN_NAME = Conventions
.getQualifiedAttributeName(EnableConfigurationPropertiesRegistrar.class, "methodValidationExcludeFilter");


@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
registerInfrastructureBeans(registry);
registerMethodValidationExcludeFilter(registry);
ConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar(registry);
getTypes(metadata).forEach(beanRegistrar::register);
}
private Set<Class<?>> getTypes(AnnotationMetadata metadata) {
return metadata.getAnnotations().stream(EnableConfigurationProperties.class)
.flatMap((annotation) -> Arrays.stream(annotation.getClassArray(MergedAnnotation.VALUE)))
.filter((type) -> void.class != type).collect(Collectors.toSet());
}
static void registerInfrastructureBeans(BeanDefinitionRegistry registry) {
ConfigurationPropertiesBindingPostProcessor.register(registry);
BoundConfigurationProperties.register(registry);
}
static void registerMethodValidationExcludeFilter(BeanDefinitionRegistry registry) {
if (!registry.containsBeanDefinition(METHOD_VALIDATION_EXCLUDE_FILTER_BEAN_NAME)) {
BeanDefinition definition = BeanDefinitionBuilder
.genericBeanDefinition(MethodValidationExcludeFilter.class,
() -> MethodValidationExcludeFilter.byAnnotation(ConfigurationProperties.class))
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE).getBeanDefinition();
registry.registerBeanDefinition(METHOD_VALIDATION_EXCLUDE_FILTER_BEAN_NAME, definition);
}
}


}

该类是一个ImportBeanDefinitionRegistrar,在springboot应用启动时,会通过ConfigurationClassPostProcessor类实例化并调用registerBeanDefinitions方法,具体可参考《ImportBeanDefinitionRegistrar原理》,我们分析一下此处的registerBeanDefinitions实现的逻辑。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
  registerInfrastructureBeans(registry);
  registerMethodValidationExcludeFilter(registry);
  ConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar(registry);
  getTypes(metadata).forEach(beanRegistrar::register);
}

里边做了三件事,分别是注册基础组件beans,注册方法校验过滤器和注册属性配置BeanDefination;先看一下注册基础组件beans:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static void registerInfrastructureBeans(BeanDefinitionRegistry registry) {
  ConfigurationPropertiesBindingPostProcessor.register(registry);
  BoundConfigurationProperties.register(registry);
}

调用ConfigurationPropertiesBindingPostProcessor的register方法注册相关信息和BoundConfigurationProperties的register方法注册相关信息,分别看一下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static void register(BeanDefinitionRegistry registry) {
  Assert.notNull(registry, "Registry must not be null");
  if (!registry.containsBeanDefinition(BEAN_NAME)) {
    BeanDefinition definition = BeanDefinitionBuilder
        .rootBeanDefinition(ConfigurationPropertiesBindingPostProcessor.class).getBeanDefinition();
    definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    registry.registerBeanDefinition(BEAN_NAME, definition);
  }
  ConfigurationPropertiesBinder.register(registry);
}

ConfigurationPropertiesBindingPostProcessor的register方法先检查是否已经注册了ConfigurationPropertiesBindingPostProcessor,如果没有则注册BeanDefination,然后调用ConfigurationPropertiesBinder的register方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static void register(BeanDefinitionRegistry registry) {
  if (!registry.containsBeanDefinition(FACTORY_BEAN_NAME)) {
    BeanDefinition definition = BeanDefinitionBuilder
        .rootBeanDefinition(ConfigurationPropertiesBinder.Factory.class).getBeanDefinition();
    definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    registry.registerBeanDefinition(ConfigurationPropertiesBinder.FACTORY_BEAN_NAME, definition);
  }
  if (!registry.containsBeanDefinition(BEAN_NAME)) {
    BeanDefinition definition = BeanDefinitionBuilder
        .rootBeanDefinition(ConfigurationPropertiesBinder.class,
            () -> ((BeanFactory) registry)
                .getBean(FACTORY_BEAN_NAME, ConfigurationPropertiesBinder.Factory.class).create())
        .getBeanDefinition();
    definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    registry.registerBeanDefinition(ConfigurationPropertiesBinder.BEAN_NAME, definition);
  }
}

这里检查有没有注册internalConfigurationPropertiesBinderFactory的BeanDefination,如果没有则注册,同样检查有没有注册internalConfigurationPropertiesBinder的BeanDefination,没有则注册备用。

回到前一步,ConfigurationPropertiesBinder调用自己的静态方法register注册自己的BeanDefination。然后回到EnableConfigurationPropertiesRegistrar的registerBeanDefinitions中调用registerMethodValidationExcludeFilter方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static void registerMethodValidationExcludeFilter(BeanDefinitionRegistry registry) {
  if (!registry.containsBeanDefinition(METHOD_VALIDATION_EXCLUDE_FILTER_BEAN_NAME)) {
    BeanDefinition definition = BeanDefinitionBuilder
        .genericBeanDefinition(MethodValidationExcludeFilter.class,
            () -> MethodValidationExcludeFilter.byAnnotation(ConfigurationProperties.class))
        .setRole(BeanDefinition.ROLE_INFRASTRUCTURE).getBeanDefinition();
    registry.registerBeanDefinition(METHOD_VALIDATION_EXCLUDE_FILTER_BEAN_NAME, definition);
  }
}

此处是检查注册MethodValidationExcludeFilter相关BeanDefination。

registerBeanDefinitions方法最后是创建ConfigurationPropertiesBeanRegistrar实例,然后从EnableConfigurationProperties注解中解析value数组,然后调用ConfigurationPropertiesBeanRegistrar实例的register方法注册ConfigurationProperties注解的相关BeanDefination,看一下ConfigurationPropertiesBeanRegistrar的register方法实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void register(Class<?> type) {
  MergedAnnotation<ConfigurationProperties> annotation = MergedAnnotations
      .from(type, SearchStrategy.TYPE_HIERARCHY).get(ConfigurationProperties.class);
  register(type, annotation);
}

解析ConfigurationProperties注解相关属性,然后进行相关BeanDefination注册,调用内部方法registerBeanDefinition:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private void registerBeanDefinition(String beanName, Class<?> type,
        MergedAnnotation<ConfigurationProperties> annotation) {
    Assert.state(annotation.isPresent(), () -> "No " + ConfigurationProperties.class.getSimpleName()
            + " annotation found on  '" + type.getName() + "'.");
    this.registry.registerBeanDefinition(beanName, createBeanDefinition(beanName, type));
}

组装BeanDefination并调用BeanDefinitionRegistry的registerBeanDefinition方法将@ConfigurationProperties注解的类注册到容器中,createBeanDefinition不再展开分析。

3.ConfigurationPropertiesBindingPostProcessor

执行属性绑定的核心是在前边分析的ConfigurationPropertiesBindingPostProcessor类中实现,继续分析一下。

ConfigurationPropertiesBindingPostProcessor本身是一个BeanPostProcessor,在应用启动阶段会调用其postProcessBeforeInitialization方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  bind(ConfigurationPropertiesBean.get(this.applicationContext, bean, beanName));
  return bean;
}

先调用ConfigurationPropertiesBean的get方法将待绑定属性目标类封装成ConfigurationPropertiesBean,然后调用内部方法bind进行绑定,先看一下ConfigurationPropertiesBean的get方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static ConfigurationPropertiesBean get(ApplicationContext applicationContext, Object bean, String beanName) {
  Method factoryMethod = findFactoryMethod(applicationContext, beanName);
  return create(beanName, bean, bean.getClass(), factoryMethod);
}

先获取工厂方法,然后调用create方法创建ConfigurationPropertiesBean:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private static ConfigurationPropertiesBean create(String name, Object instance, Class<?> type, Method factory) {
  ConfigurationProperties annotation = findAnnotation(instance, type, factory, ConfigurationProperties.class);
  if (annotation == null) {
    return null;
  }
  Validated validated = findAnnotation(instance, type, factory, Validated.class);
  Annotation[] annotations = (validated != null) ? new Annotation[] { annotation, validated }
      : new Annotation[] { annotation };
  ResolvableType bindType = (factory != null) ? ResolvableType.forMethodReturnType(factory)
      : ResolvableType.forClass(type);
  Bindable<Object> bindTarget = Bindable.of(bindType).withAnnotations(annotations);
  if (instance != null) {
    bindTarget = bindTarget.withExistingValue(instance);
  }
  return new ConfigurationPropertiesBean(name, instance, annotation, bindTarget);
}

这里获取bean上是否有ConfigurationProperties注解,如果没有则不需要绑定,直接返回null,否则将目标bean封装成ConfigurationPropertiesBean实例返回备用。

这里细心的小伙伴可以发现,有一个可以优化的地方,前边先寻找工厂方法,然后检查是否需要绑定,如果前边执行过了,但是没有解析到ConfigurationProperties注解,这里就返回了,前边的调用就是无用功,所以这里检查的位置或者调用顺序需要调整优化,可以自行思考。

言归正传,回到前边调用私有方法bind进行属性绑定的调用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private void bind(ConfigurationPropertiesBean bean) {
  if (bean == null || hasBoundValueObject(bean.getName())) {
    return;
  }
  Assert.state(bean.getBindMethod() == BindMethod.JAVA_BEAN, "Cannot bind @ConfigurationProperties for bean '"
      + bean.getName() + "'. Ensure that @ConstructorBinding has not been applied to regular bean");
  try {
    this.binder.bind(bean);
  }
  catch (Exception ex) {
    throw new ConfigurationPropertiesBindException(bean, ex);
  }
}

会继续调用ConfigurationPropertiesBinder的bind方法进行绑定,前边有分析过ConfigurationPropertiesBinder在EnableConfigurationPropertiesRegistrar的registerBeanDefinitions方法注册BeanDefination,在应用启动时会实例化,看一下ConfigurationPropertiesBinder的bind方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
BindResult<?> bind(ConfigurationPropertiesBean propertiesBean) {
  Bindable<?> target = propertiesBean.asBindTarget();
  ConfigurationProperties annotation = propertiesBean.getAnnotation();
  BindHandler bindHandler = getBindHandler(target, annotation);
  return getBinder().bind(annotation.prefix(), target, bindHandler);
}

从ConfigurationPropertiesBean获取绑定目标和注解,然后获取BindHandler,最后获取Binder进行属性绑定,属性绑定会调用Binder类的bind方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public <T> BindResult<T> bind(String name, Bindable<T> target, BindHandler handler) {
    return bind(ConfigurationPropertyName.of(name), target, handler);
}

继续调用重载方法bind进行绑定:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public <T> BindResult<T> bind(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler) {
    T bound = bind(name, target, handler, false);
    return BindResult.of(bound);
}

然后会调用私有方法bind进行绑定:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private <T> T bind(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler, Context context,
    boolean allowRecursiveBinding, boolean create) {
  try {
    Bindable<T> replacementTarget = handler.onStart(name, target, context);
    if (replacementTarget == null) {
      return handleBindResult(name, target, handler, context, null, create);
    }
    target = replacementTarget;
    Object bound = bindObject(name, target, handler, context, allowRecursiveBinding);
    return handleBindResult(name, target, handler, context, bound, create);
  }
  catch (Exception ex) {
    return handleBindError(name, target, handler, context, ex);
  }
}

核心逻辑是bindObject方法调用,传入属性名、目标绑定对象等进行绑定操作。按照我们前边实例定义的属性格式会走到如下方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private Object bindDataObject(ConfigurationPropertyName name, Bindable<?> target, BindHandler handler,
    Context context, boolean allowRecursiveBinding) {
  if (isUnbindableBean(name, target, context)) {
    return null;
  }
  Class<?> type = target.getType().resolve(Object.class);
  if (!allowRecursiveBinding && context.isBindingDataObject(type)) {
    return null;
  }
  DataObjectPropertyBinder propertyBinder = (propertyName, propertyTarget) -> bind(name.append(propertyName),
      propertyTarget, handler, context, false, false);
  return context.withDataObject(type, () -> {
    for (DataObjectBinder dataObjectBinder : this.dataObjectBinders) {
      Object instance = dataObjectBinder.bind(name, target, context, propertyBinder);
      if (instance != null) {
        return instance;
      }
    }
    return null;
  });
}

根据前边绑定方式是BindMethod.JAVA_BEAN,所以会走到JavaBeanBinder类的bind方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public <T> T bind(ConfigurationPropertyName name, Bindable<T> target, Context context,
    DataObjectPropertyBinder propertyBinder) {
  boolean hasKnownBindableProperties = target.getValue() != null && hasKnownBindableProperties(name, context);
  Bean<T> bean = Bean.get(target, hasKnownBindableProperties);
  if (bean == null) {
    return null;
  }
  BeanSupplier<T> beanSupplier = bean.getSupplier(target);
  boolean bound = bind(propertyBinder, bean, beanSupplier, context);
  return (bound ? beanSupplier.get() : null);
}

属性绑定最终会调用到JavaBeanBinder的私有方法bind:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  private <T> boolean bind(BeanSupplier<T> beanSupplier, DataObjectPropertyBinder propertyBinder,
      BeanProperty property) {
    String propertyName = property.getName();
    ResolvableType type = property.getType();
    Supplier<Object> value = property.getValue(beanSupplier);
    Annotation[] annotations = property.getAnnotations();
    Object bound = propertyBinder.bindProperty(propertyName,
        Bindable.of(type).withSuppliedValue(value).withAnnotations(annotations));
    if (bound == null) {
      return false;
    }
    if (property.isSettable()) {
      property.setValue(beanSupplier, bound);
    }
    else if (value == null || !bound.equals(value.get())) {
      throw new IllegalStateException("No setter found for property: " + property.getName());
    }
    return true;
  }

到这里就完成了应用配置文件中属性绑定到配置类的操作,整个流程大致如下:

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-08-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 PersistentCoder 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
1 条评论
热度
最新
我也出现这个问题,站点也配置好了,备案也通过了,依然不行
我也出现这个问题,站点也配置好了,备案也通过了,依然不行
回复回复点赞举报
推荐阅读
基于服务器的个人博客网站搭建
服务器与本地xshell连接,就像连接Linux系统一样,只是ip写成服务器的公网ip。
CoreDao
2021/04/13
4.2K0
基于服务器的个人博客网站搭建
宝塔面板登录不上:请使用正确的入口登录面板
则在端口号后加上即可,如 http://公网ip:8888/8位随机数。访问即可。
CoreDao
2021/04/13
13.9K0
宝塔面板登录不上:请使用正确的入口登录面板
基于wordpress零基础纯新手向-2022最新最全面最详细教程-教你一步一步搭建自己的网站
我们日常生活工作都会浏览各式各样的网站,在这期间你是否也想过搭建一个属于自己的网站、博客,来分享、讨论、交流你的专业知识和兴趣爱好、展示自己的生活状态和艺术作品?
望舒瑾
2022/05/31
4.1K1
基于wordpress零基础纯新手向-2022最新最全面最详细教程-教你一步一步搭建自己的网站
关于网站备案的那些事情
  随着社会的不断进步和信息技术的不断发展,为了避免一些不良信息的传播,网站备案服务也必不可少,那么网站备案的意义何在?以下便宜技术猫将与大家分享:
幻影龙王
2021/09/08
1.7K0
关于网站备案的那些事情
怎么建网站问答:正在备案怎么建网站
在昨天的文章里面分享了自己搭建网站需要备案吗的答案,那么可能又有小伙伴要问了,正在备案怎么建网站?
奶爸建站笔记
2019/06/20
6.7K0
怎么建网站问答:正在备案怎么建网站
详细!完成备案需要多久时间?国内网站备案流程与步骤
  上一篇文章主要讲解了WordPress主题的设置,距离完成一个完整的个人网站搭建还差最后一步。
IT学习日记
2022/09/13
17.9K1
详细!完成备案需要多久时间?国内网站备案流程与步骤
新手建站之【创建站点】⑤
新手建站合集 1️⃣新手建站之【域名注册】①http://t.csdn.cn/y8gM3✅ 2️⃣新手建站之【服务器租用】②http://t.csdn.cn/tlIWK✅ 3️⃣新手建站之【网站备案】③http://t.csdn.cn/P9G6W✅ 4️⃣新手建站之【建站环境安装】④http://t.csdn.cn/j65D9✅ 5️⃣新手建站之【创建站点】⑤http://t.csdn.cn/5N2Ss✅ 6️⃣新手建站之【站点设置】⑥http://t.csdn.cn/sdqjV✅ 7️⃣新手建站之【域名解析】⑦http://t.csdn.cn/CFUOb✅ 8️⃣新手建站之【源码上传】⑧http://t.csdn.cn/Me1WY✅
MIKE笔记
2023/03/23
10.5K0
新手建站之【创建站点】⑤
腾讯云网站备案咨询解答:其他问题解答汇总
腾讯云网站备案类的提问还是很多的,因为不断有人遇到各种情况,所以各种问题层出不穷。但是无论怎么提问也还是都是围绕着网站备案、准备资料、备案过程这几个核心的,所以老魏继续总结了一些其他问题解答汇总,分享给大家。
魏艾斯博客www.vpsss.net
2019/10/19
7.7K0
腾讯云网站备案咨询解答:其他问题解答汇总
【有奖征文】用轻量云快速搭建BT面板+创建站点(Liunx)
宝塔Linux面板是提升运维效率的服务器管理软件,支持一键LAMP/LNMP/集群/监控/网站/FTP/数据库/JAVA等100多项服务器管理功能。对新手而言非常友好,能快速的管理自己的服务器和网站。
用户8403842
2022/03/25
1K0
【有奖征文】用轻量云快速搭建BT面板+创建站点(Liunx)
小白安装Discuz!Q教程,学不会你过来打我!
你知道吗?小白也可以安装Discuz!Q啦!你不需要敲代码也不用懂太多的技术,严格按照下面的安装教程操作,就可以成功安装上Discuz!Q。 在开始之前,我们先来了解一下,安装Discuz!Q的两大要素是:域名和服务器。简单来说,域名是用来打开网站的大门,在浏览器上输入域名,你就能打开相应的网页;而云服务器则是一个用来存放网站内容的地方。 当然,想要让别人正常访问你搭建的站点,你需要给网站做备案;想要使用域名打开相应的站点,你需要将域名解析到对应的IP地址;想要在浏览器上安全访问你的站点,你还需要安装SS
腾讯云DNSPod团队
2020/06/28
10.5K3
Toradora网站备案以及全站加速
当前的站点其实是暂时未进行备案注册的,因为服务器未在境内,无法进行备案。但是未备案的话,无法使用国内的CDN加速服务,在国内的搜索引擎中中指不定哪天就被毙了。所以在前不久搭建的一个网站中,还是走的正规军的流程。
Diuut
2022/11/22
6.6K0
【玩转 WordPress】基于Mac的手动搭建WordPress个人站点的方法
WordPress是一款通过使用PHP语言开发的博客平台,开发者可以通过WordPress搭建属于自己的个人博客平台,本篇博文以Mac操作系统为例,手动搭建WordPress个人站点。
三掌柜
2021/05/16
3.9K4
【玩转 WordPress】基于Mac的手动搭建WordPress个人站点的方法
网站备案前一定要检查这些域名隐患和网站名称规范
网站备案是域名+主机的一体化过程,而域名是网站备案的载体。一般网站备案的展现形式是在域名上的。所以域名对网站备案是很重要的哦!
乐网网络
2019/04/14
16.9K1
服务器使用宝塔面板出现“您的请求在web服务器中没有找到对应的站点!”的解决办法
这个提示是说您访问的域名,在这台服务器上没有找到对应的站点,其实就是配置文件没有正确读取才出现的。
for fun
2018/07/27
10.2K1
服务器使用宝塔面板出现“您的请求在web服务器中没有找到对应的站点!”的解决办法
腾讯云网站备案咨询:网站信息类问题汇总解答
腾讯云网站备案时,关于网站信息的相关问题不少。此类问题围绕着网站备案、准备资料、备案过程这几个核心,老魏陆续汇总了一些相关问题答案,分享给大家。
魏艾斯博客www.vpsss.net
2019/10/23
10.8K0
腾讯云网站备案咨询:网站信息类问题汇总解答
手动搭建 WordPress 个人站点(Windows)
WordPress 是一款使用 PHP 语言开发的博客平台,您可使用通过 WordPress 搭建属于个人的博客平台。本文以 Windows Server 2012 操作系统的腾讯云云服务器为例,手动搭建 WordPress 个人站点。
用户10230909
2023/04/25
11.5K1
宝塔面板部署Nextcloud后解决后台安全错误及设置警告
当我们使用宝塔面板部署好后,可以直接使用,如果你还没有部署Nextcloud,可以参考:
Mintimate
2021/02/16
19.2K2
宝塔面板部署Nextcloud后解决后台安全错误及设置警告
【干货】保姆级超细教程从购买服务器到网站搭建成功!
云服务器(Elastic Compute Service, ECS)是一种简单高效、安全可靠、处理能力可弹性伸缩的计算服务。其管理方式比物理服务器更简单高效。用户无需提前购买硬件,即可迅速创建或释放任意多台云服务器。
释然IT杂谈
2022/10/27
5K0
【干货】保姆级超细教程从购买服务器到网站搭建成功!
多账号管理和一个账号管理多个网站的网站后台管理SaaS系统在腾讯云服务器部署教程
多站点CMS网站内容管理后台可以管理多个网站,由于客户有多个公司,开发多个网站,可是按照传统CMS管理系统只能是一个后台管理一个网站,而且还需要独立部署;对开发和维护也麻烦,用户后期管理网站也麻烦(需要管理对个后台账号密码)。还有很多后台是php开发的,政府性网站经常遭到同行攻击,主要还是和php不可编译有关。所以综合以上种种,结合Go和PHP各自优点开发一套CMS内容管理后台,支持多个企业账号、多个站点、在线编辑网站,无需每次建站都部署,一次部署即可一直新增网站和开客户账号即可(不再像以前一个家一家单独部署),目前CMS已经用于实际企业网站管理,并在维护中比以前要省心,一套系统要做运行正常,所有网站都正常,您可以根据需要二次开发,例如:域名到期提醒,SSL证书到期提醒,用户维护未到期提醒等等。
用户2848031
2023/08/23
1.3K0
多账号管理和一个账号管理多个网站的网站后台管理SaaS系统在腾讯云服务器部署教程
使用腾讯云轻量服务器安装雷池结合宝塔面板为你的网站保驾护航 | 技术创作特训营第一期
前不久在开源中国看到一款叫长亭雷池的防火墙软件,在自己的博客站上实验了一下效果不错,听说腾讯云又在做服务器的活动,所以将网站加固的过程在免费体验服上梳理了一遍,希望能帮助到更多同学保护自己的站点服务。
薛定喵君
2023/08/13
3K2
推荐阅读
相关推荐
基于服务器的个人博客网站搭建
更多 >
LV.0
这个人很懒,什么都没有留下~
目录
  • 1.定义属性配置
  • 2.定义对应属性配置类
  • 3.定义自动配置类
  • 4.使用属性配置
  • 二、原理介绍
    • 1.@EnableConfigurationProperties注解
    • 2.EnableConfigurationPropertiesRegistrar
    • 3.ConfigurationPropertiesBindingPostProcessor
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档