ImportBeanDefinitionRegistrar手动控制BeanDefinition创建注册详解

目录
  • 一、什么是ImportBeanDefinitionRegistrar
  • 二、ImportBeanDefinitionRegistrar使用很简单
    • registerFilters()方法
  • 三、ImportBeanDefinitionRegistrar原理

一、什么是ImportBeanDefinitionRegistrar

ImportBeanDefinitionRegistrar接口是也是spring的扩展点之一,ImportBeanDefinitionRegistrar类只能通过其他类 @Import的方式来加载,通常是启动类或配置类。它可以支持我们自己写的代码封装成BeanDefinition对象;实现此接口的类会回调postProcessBeanDefinitionRegistry方法,注册到spring容器中。

把bean注入到spring容器不止有 @Service @Component等注解方式;还可以实现此接口,这种方式是最灵活的,能在registerBeanDefinitions方法中获取到BeanDefinitionRegistry容器注册对象,可以手动控制BeanDefinition的创建和注册。

public interface ImportBeanDefinitionRegistrar {
    default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
        this.registerBeanDefinitions(importingClassMetadata, registry);
    }
    default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    }
}

二、ImportBeanDefinitionRegistrar使用很简单

加载指定类

定义一个类TestImportBeanDefinitionRegistrar实现ImportBeanDefinitionRegistrar接口,在配置类TestConfiguration加上注解@Import一个TestImportBeanDefinitionRegistrar实现类,重写registerBeanDefinitions方法,手动注册bean,实现注册BeanDefinition到容器中,也可以实现一些Aware接口,以便获取Spring的一些数据。加载指定DataSource类如下:

public class TestImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar,ResourceLoaderAware,BeanFactoryAware {
    private static ResourceLoader resourceLoader;
    private static BeanFactory beanFactory;
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
      //创建DataSourceBean
      GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
      beanDefinition.setBeanClass(DataSource.class);
      beanDefinition.setSynthetic(true);
      MutablePropertyValues mpv = beanDefinition.getPropertyValues();
      //spring名称约定为defaultTargetDataSource和targetDataSources
      mpv.addPropertyValue("defaultTargetDataSource", defaultTargetDataSource);
      mpv.addPropertyValue("targetDataSources", DataSourceSet.getTargetDataSourcesMap());
      beanDefinitionRegistry.registerBeanDefinition("dataSource", beanDefinition);
    }
      @Override
      public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
          this.beanFactory=beanFactory;
      }
      @Override
      public void setResourceLoader(ResourceLoader resourceLoader) {
          this.resourceLoader=resourceLoader;
      }
}
@Import(TestImportBeanDefinitionRegistrar.class)
@Configuration
public class TestConfiguration {
}

这样就注册了一个bean名字是dataSource,有两个属性分别是defaultTargetDataSource和targetDataSources。那么使用这个类直接用 @Autowired和@Resource注入即可。

加载扫描器类

如果我们并不知道需要register哪些bean。这里我们还需要借助一个扫描器类ClassPathBeanDefinitionScanner,通过扫描器获取我们需要注册的bean。首先创建一个@Mapper注解,再新建一个CountryMapper类,使用该Mapper注解。

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
public @interface Mapper {
}
@Mapper
public class CountryMapper {
}

创建一个MyClassPathBeanDefinitionScanner类继承ClassPathBeanDefinitionScanner,扫描使用@Mapper的注解的类,ClassPathBeanDefinitionScanner又继承ClassPathScanningCandidateComponentProvider类,ClassPathScanningCandidateComponentProvider中有两个TypeFilter集合,includeFilters、excludeFilters。满足任意includeFilters会被加载,同样的满足任意excludeFilters不会被加载。

@Slf4j
public class MyClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner{
    public MyClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
        super(registry, useDefaultFilters);
    }
    protected void registerFilters() {
        addIncludeFilter(new AnnotationTypeFilter(Mapper.class));
    }
    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        return super.doScan(basePackages);
    }
}

registerFilters()方法

核心代码就是registerFilters()方法,然后在我们的ImportBeanDefinitionRegistrar实现类中调用:

public class MapperAutoConfiguredMyBatisRegistrar
        implements ImportBeanDefinitionRegistrar{
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        MyClassPathBeanDefinitionScanner scanner = new MyClassPathBeanDefinitionScanner(registry, false);
        scanner.setResourceLoader(resourceLoader);
        scanner.registerFilters();
        scanner.doScan("com.faderw.school.domain");
    }
}

这里我们自定义带有@Mapper注解的类CountryMapper就被注入到IOC容器了,可以直接使用噢。

三、ImportBeanDefinitionRegistrar原理

TestImportBeanDefinitionRegistrar是被TestConfiguration类import导入的,所以要加载到TestImportBeanDefinitionRegistrar必然要先加载TestConfiguration才行;所以先看Configuration的代码,找到ConfigurationClassPostProcessor类,它实现了BeanDefinitionRegistryPostProcessor接口

Map<String, BeanDefinitionRegistryPostProcessor> beanMap =
					beanFactory.getBeansOfType(BeanDefinitionRegistryPostProcessor.class, true, false);
List<BeanDefinitionRegistryPostProcessor> registryPostProcessorBeans =
		new ArrayList<BeanDefinitionRegistryPostProcessor>(beanMap.values());
OrderComparator.sort(registryPostProcessorBeans);
for (BeanDefinitionRegistryPostProcessor postProcessor : registryPostProcessorBeans) {
	postProcessor.postProcessBeanDefinitionRegistry(registry);
}

从spring容器中拿到实现了BeanDefinitionRegistryPostProcessor接口的类。拿到后执行对应的postProcessBeanDefinitionRegistry方法:

        //从invokeBeanFactoryPostProcessors方法调过来
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
		RootBeanDefinition iabpp = new RootBeanDefinition(ImportAwareBeanPostProcessor.class);
		iabpp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(IMPORT_AWARE_PROCESSOR_BEAN_NAME, iabpp);
		//取得registry的id并做判重处理或记录
		int registryId = System.identityHashCode(registry);
		if (this.registriesPostProcessed.contains(registryId)) {
			throw new IllegalStateException(
					"postProcessBeanDefinitionRegistry already called for this post-processor against " + registry);
		}
		if (this.factoriesPostProcessed.contains(registryId)) {
			throw new IllegalStateException(
					"postProcessBeanFactory already called for this post-processor against " + registry);
		}
		//保存处理过的registry,避免重复处理
		this.registriesPostProcessed.add(registryId);
		 //处理java配置形式的bean定义
		processConfigBeanDefinitions(registry);
	}

最后调用了processConfigBeanDefinitions方法处理java配置形式的bean定义:

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		Set<BeanDefinitionHolder> configCandidates = new LinkedHashSet<BeanDefinitionHolder>();
		//加载当前已知所有bean定义
		for (String beanName : registry.getBeanDefinitionNames()) {
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
			//   判断对应bean是否为配置类,如果是,则加入到configCandidates
			// @Configuration, @Component, @ComponentScan, @Import, @Bean等注解
			if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}
		//如果找不到@configuration类,则立即返回
		if (configCandidates.isEmpty()) {
			return;
		}
...........
		 // 实例化ConfigurationClassParser 为了解析 各个配置类
		ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);
		for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			System.out.println("ConfigurationClassPostProcessor bd " + bd.getBeanClassName());
			try {
				if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
					parser.parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
				}
				else {
					parser.parse(bd.getBeanClassName(), holder.getBeanName());
				}
			}
			catch (IOException ex) {
				throw new BeanDefinitionStoreException("Failed to load bean class: " + bd.getBeanClassName(), ex);
			}
		}
		parser.validate();
......

ConfigurationClassParser#parse方法:

 public void parse(String className, String beanName) throws IOException {
        MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
        processConfigurationClass(new ConfigurationClass(reader, beanName));
}

processConfigurationClass方法:

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
        ...................
        do {
             //重点
             metadata = doProcessConfigurationClass(configClass, metadata);
        }
        while (metadata != null);
 .................
}

doProcessConfigurationClass方法:

protected AnnotationMetadata doProcessConfigurationClass(ConfigurationClass configClass, AnnotationMetadata metadata) throws IOException {
		// Recursively process any member (nested) classes first
		processMemberClasses(metadata);
		// Process any @PropertySource annotations
		//处理@PropertySource  加载外面资源文件
		AnnotationAttributes propertySource = MetadataUtils.attributesFor(metadata,
				org.springframework.context.annotation.PropertySource.class);
		if (propertySource != null) {
			processPropertySource(propertySource);
		}
		// Process any @ComponentScan annotations
		//处理  @ComponentScan 扫描包
		AnnotationAttributes componentScan = MetadataUtils.attributesFor(metadata, ComponentScan.class);
		if (componentScan != null) {
			// The config class is annotated with @ComponentScan -> perform the scan immediately
			Set<BeanDefinitionHolder> scannedBeanDefinitions =
					this.componentScanParser.parse(componentScan, metadata.getClassName());
			// Check the set of scanned definitions for any further config classes and parse recursively if necessary
			for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
				if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {
					this.parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
				}
			}
		}
		//处理@Import注解
		// Process any @Import annotations
		Set<Object> imports = new LinkedHashSet<Object>();
		Set<String> visited = new LinkedHashSet<String>();
		collectImports(metadata, imports, visited);
		if (!imports.isEmpty()) {
			processImport(configClass, metadata, imports, true);
		}
		// Process any @ImportResource annotations
		if (metadata.isAnnotated(ImportResource.class.getName())) {
			AnnotationAttributes importResource = MetadataUtils.attributesFor(metadata, ImportResource.class);
			String[] resources = importResource.getStringArray("value");
			Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
			for (String resource : resources) {
				String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
				configClass.addImportedResource(resolvedResource, readerClass);
			}
		}
		// Process individual @Bean methods
		//处理@Bean注解
		Set<MethodMetadata> beanMethods = metadata.getAnnotatedMethods(Bean.class.getName());
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}
		// Process superclass, if any
		if (metadata.hasSuperClass()) {
			String superclass = metadata.getSuperClassName();
			if (!superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
				this.knownSuperclasses.put(superclass, configClass);
				// superclass found, return its annotation metadata and recurse
				if (metadata instanceof StandardAnnotationMetadata) {
					Class<?> clazz = ((StandardAnnotationMetadata) metadata).getIntrospectedClass();
					return new StandardAnnotationMetadata(clazz.getSuperclass(), true);
				}
				else {
					MetadataReader reader = this.metadataReaderFactory.getMetadataReader(superclass);
					return reader.getAnnotationMetadata();
				}
			}
		}
		// No superclass -> processing is complete
		return null;
	}

processImport方法:

 private void processImport(ConfigurationClass configClass, AnnotationMetadata metadata,
			Collection<?> classesToImport, boolean checkForCircularImports) throws IOException {
        if (checkForCircularImports && this.importStack.contains(configClass)) {
            this.problemReporter.error(new CircularImportProblem(configClass, this.importStack, configClass.getMetadata()));
        }else {
            this.importStack.push(configClass);
            try {
                for (Object candidate : classesToImport) {
                        Object candidateToCheck = (candidate instanceof Class ? (Class) candidate :
                                        this.metadataReaderFactory.getMetadataReader((String) candidate));
                        //实现ImportSelector接口的处理
                        if (checkAssignability(ImportSelector.class, candidateToCheck)) {
                                // Candidate class is an ImportSelector -> delegate to it to determine imports
                                Class<?> candidateClass = (candidate instanceof Class ? (Class) candidate :
                                                this.resourceLoader.getClassLoader().loadClass((String) candidate));
                                ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
                                processImport(configClass, metadata, Arrays.asList(selector.selectImports(metadata)), false);
                        }
                        //实现ImportBeanDefinitionRegistrar接口的处理
                        else if (checkAssignability(ImportBeanDefinitionRegistrar.class, candidateToCheck)) {
                                // Candidate class is an ImportBeanDefinitionRegistrar ->
                                // delegate to it to register additional bean definitions
                                Class<?> candidateClass = (candidate instanceof Class ? (Class) candidate :
                                                this.resourceLoader.getClassLoader().loadClass((String) candidate));
                                ImportBeanDefinitionRegistrar registrar =
                                                BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
                                invokeAwareMethods(registrar);
                                //调用该类的registerBeanDefinitions方法
                                registrar.registerBeanDefinitions(metadata, this.registry);
                        }
                        else {
                                //候选类不是importSelector或importBeanDefinitionRegistrar
                                //@Configuration类的处理
                                // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
                                // process it as a @Configuration class
                                this.importStack.registerImport(metadata,
                                                (candidate instanceof Class ? ((Class) candidate).getName() : (String) candidate));
                                processConfigurationClass(candidateToCheck instanceof Class ?
                                                new ConfigurationClass((Class) candidateToCheck, true) :
                                                new ConfigurationClass((MetadataReader) candidateToCheck, true));
                        }
                }
        }
        catch (ClassNotFoundException ex) {
                throw new NestedIOException("Failed to load import candidate class", ex);
        }
        finally {
                this.importStack.pop();
        }
    }
}

最终调用了DefaultListableBeanFactory的registerBeanDefinition方法,这里就是处理ImportBeanDefinitionRegistrar接口实现类的地方:

 public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {
        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");
        if("configurationTest".equals(beanName)){
                System.out.println(" registerBeanDefinition(String beanName, BeanDefinition beanDefinition) " + beanName);
        }
        if (beanDefinition instanceof AbstractBeanDefinition) {
                try {
                        ((AbstractBeanDefinition) beanDefinition).validate();
                }
                catch (BeanDefinitionValidationException ex) {
                        throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                                        "Validation of bean definition failed", ex);
                }
        }
          // old? 还记得 “允许 bean 覆盖” 这个配置吗?allowBeanDefinitionOverriding
        BeanDefinition oldBeanDefinition;
        synchronized (this.beanDefinitionMap) {
                  // 之后会看到,所有的 Bean 注册后会放入这个 beanDefinitionMap 中
                oldBeanDefinition = this.beanDefinitionMap.get(beanName);
                // 处理重复名称的 Bean 定义的情况
                if (oldBeanDefinition != null) {
                        if (!this.allowBeanDefinitionOverriding) {
                                 // 如果不允许覆盖的话,抛异常
                                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                                                "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                                                "': There is already [" + oldBeanDefinition + "] bound.");
                        }
                        else {
                                if (this.logger.isInfoEnabled()) {
                                        this.logger.info("Overriding bean definition for bean '" + beanName +
                                                        "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
                                }
                        }
                }
                else {
                        //添加beanDefinitionNames
                        this.beanDefinitionNames.add(beanName);
                        this.frozenBeanDefinitionNames = null;
                }
                // 覆盖
                this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        if (oldBeanDefinition != null || containsSingleton(beanName)) {
                resetBeanDefinition(beanName);
        }
}
public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
    Assert.hasText(beanName, "'beanName' must not be empty");
    synchronized (this.beanDefinitionMap) {
            BeanDefinition bd = this.beanDefinitionMap.remove(beanName);
            if (bd == null) {
                    if (this.logger.isTraceEnabled()) {
                            this.logger.trace("No bean named '" + beanName + "' found in " + this);
                    }
                    throw new NoSuchBeanDefinitionException(beanName);
            }
            this.beanDefinitionNames.remove(beanName);
            this.frozenBeanDefinitionNames = null;
    }
    resetBeanDefinition(beanName);
}

这段代码主要就是把定义的bean放到beanDefinitionMap里去。beanDefinitionMap维护的就是bean的定义,当需要获取的时候就从里面拿到对应的BeanDefinition,根据BeanDefinition生成一个对象

以上就是ImportBeanDefinitionRegistrar手动控制BeanDefinition创建注册详解的详细内容,更多关于BeanDefinition创建注册的资料请关注我们其它相关文章!

(0)

相关推荐

  • Spring超详细讲解创建BeanDefinition流程

    目录 一.前期准备 1.1 环境依赖 1.2 实体类 1.3 applicationContext.xml 1.4 测试代码 二.探究过程 2.1 目标 2.2 BeanDefinition的创建过程 2.2.1 回顾bean对象的创建 2.2.2 AbstractApplicationContext 2.2.3 AbstractXmlApplicationContext 2.2.4 AbstractBeanDefinitionReader 2.2.5 XmlBeanDefinitionRead

  • SpringIOC BeanDefinition的加载流程详解

    目录 一.前言 二. BeanDefinition 的体系 2.1 体系概览 2.2 BeanDefinition 的作用 三. BeanDefinition 的载入 3.1 载入的入口 3.2 保存的逻辑 3.3 使用的方式 总结 一.前言 这一篇来看看 SpringIOC 里面的一个细节点 , 来简单看看 BeanDefinition 这个对象 , 以及有没有办法对其进行定制. CASE 备份 :  gitee.com/antblack/ca… 二. BeanDefinition 的体系 2

  • BeanDefinitionRegistryPostProcessor如何动态注册Bean到Spring

    目录 1.理论 2.实战代码 总结下 1.理论 一般如果想将类注册到spring容器,让spring来完成实例化,常用方式如下: xml中通过bean节点来配置: 使用@Service.@Controller.@Conponent等注解. 最近在研究通过Spring初始化时扫描自定义注解,查到了通过实现BeanDefinitionRegistryPostProcessor获取Bean,从而获得自定义注解. Spring支持我们通过代码来将指定的类注册到spring容器中. Spring容器初始化

  • Bean实例化之前修改BeanDefinition示例详解

    目录 BeanFactory 通过BeanDefinition对象实例化Bean对象 BeanFactory BeanFactory是Spring中容器功能的基础,用于存放所有已经加载的bean,为了保证程序上的高可扩展性,Spring针对BeanFactory做了大量的扩展.BeanFactoryPostProcessor是BeanFactory的后置处理器:比如在postProcessBeanFactory方法中,可以获取BeanDefinition的相关对象,并且修改该对象的属性. @Fu

  • 如何利用Spring把元素解析成BeanDefinition对象

    目录 前言 1.BeanDefinition 2.BeanDefinitionParserDelegate 2.1.parseBeanDefinitionElement 2.2.parseBeanDefinitionElement 2.3 parseBeanDefinitionAttributes 2.4 parseConstructorArgElement 3 总结 前言 spring中解析元素最重要的一个对象应该就属于 BeanDefinition了:这个Spring容器中最基本的内部数据结

  • Spring注解驱动之BeanDefinitionRegistryPostProcessor原理解析

    目录 BeanDefinitionRegistryPostProcessor概述 案例实践 源码分析 小结 BeanDefinitionRegistryPostProcessor概述 可以看到BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子接口. 注释中说执行时机是所有合法的bean定义已经加载,但是还没实例化. 看起来和BeanFactoryPostProcessor执行时机差不多,但是BeanFactoryPostP

  • ImportBeanDefinitionRegistrar手动控制BeanDefinition创建注册详解

    目录 一.什么是ImportBeanDefinitionRegistrar 二.ImportBeanDefinitionRegistrar使用很简单 registerFilters()方法 三.ImportBeanDefinitionRegistrar原理 一.什么是ImportBeanDefinitionRegistrar ImportBeanDefinitionRegistrar接口是也是spring的扩展点之一,ImportBeanDefinitionRegistrar类只能通过其他类 @

  • 使用vs2019加.net core 对WeiApi的创建过程详解

    vs2019创建webapi 1.创建新的项目 2.选择.NET CORE的ASP .NET CORE WEB应用程序 3.定义项目名称和存放地点 4.选择API创建项目 5.删除原本的无用的类 6.添加新的方法类 7.设置路由 using Microsoft.AspNetCore.Components; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks;

  • RocketMQ源码解析topic创建机制详解

    目录 1. RocketMQ Topic创建机制 2. 自动Topic 3. 手动创建--预先创建 通过界面控制台创建 1. RocketMQ Topic创建机制 以下源码基于Rocket MQ 4.7.0 RocketMQ Topic创建机制分为两种:一种自动创建,一种手动创建.可以通过设置broker的配置文件来禁用或者允许自动创建.默认是开启的允许自动创建 autoCreateTopicEnable=true/false 下面会结合源码来深度分析一下自动创建和手动创建的过程. 2. 自动T

  • Java 利用dom方式读取、创建xml详解及实例代码

    Java 利用dom方式读取.创建xml详解 1.创建一个接口 XmlInterface.Java public interface XmlInterface { /** * 建立XML文档 * @param fileName 文件全路径名称 */ public void createXml(String fileName); /** * 解析XML文档 * @param fileName 文件全路径名称 */ public void parserXml(String fileName); }

  • Android 逐帧动画创建实例详解

    Android 逐帧动画创建实例详解 前言: 我们看早期电影的时候,电影通常是一张一张播放,用我们现在专有名词来说,就是一帧帧来,安卓同样有这样动画效果的编排形式. 那么我们先定义逐帧动画xml文件 <?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" an

  • 第九篇Bootstrap导航菜单创建步骤详解

    创建一个标签式的导航菜单的步骤是: •在ul标签上加上class  nav •再ul标签上加上 class .nav-tabs. 在li标签上加上 active表示激活该项 <ul class="nav nav-tabs"> <li class="active"><a href="#">Home</a></li> <li><a href="#">

  • shell脚本 自动创建用户详解及实例代码

    shell脚本 自动创建用户详解 需求:判断用户zhangsan是否存在,不存在就创建并设置密码为123456 1.vi createuser.sh 2.写入: USER_COUNT=`cat /etc/passwd | grep '^zhangsan:' -c` USER_NAME='zhangsan' if [ $USER_COUNT -ne 1 ] then useradd $USER_NAME echo "123456" | passwd $USER_NAME --stdin

  • 基于String变量的两种创建方式(详解)

    在java中,有两种创建String类型变量的方式: String str01="abc";//第一种方式 String str02=new String("abc")://第二种方式 第一种方式创建String变量时,首先查找JVM方法区的字符串常量池是否存在存放"abc"的地址,如果存在,则将该变量指向这个地址,不存在,则在方法区创建一个存放字面值"abc"的地址. 第二种方式创建String变量时,在堆中创建一个存放&q

  • spring实现bean对象创建代码详解

    我以一个简单的示例解构spring是怎样管理java对象的. 首先,定义一个简单的pojo,代码如下: package com.jvk.ken.spring; public class Demo { private String name; public Demo() { name="I'm Demo."; } public void printName() { System.out.println(name); } public void setName(String name) {

  • Java数组的声明与创建示例详解

    今天在刷Java题的时候,写惯了C++发现忘记了Java数组的操作,遂把以前写的文章发出来温习一下. 首先,数组有几种创建方式? Java程序中的数组必须先进行初始化才可以使用,所谓初始化,就是为数组对象的元素分配内存空间,并为每个数组元素指定初始值,而在Java中,数组是静态的,数组一旦初始化,长度便已经确定,不能再随意更改. 声明数组变量 首先必须声明数组变量,才能在程序中使用数组.下面是声明数组变量的语法: dataType[] arrayRefVar; // 首选的方法 或 dataTy

随机推荐