如何利用Spring的@Import扩展点与spring进行无缝整合

利用Spring的@Import扩展与spring进行无缝整合前言BeanFactoryPostProcessor@Import实现POM文件定义数据层Resource(dao)层的扫描注解定义我的数据层Resource使用的注解ArteryResourceImportBeanDefinitionRegistrar实现自定义扫描类ClassPathArteryResourceScanner代理注册工厂ResourceRegistryResouce的代理工厂真正的代理类方法调用类AbstractBeanDefinitionFactory我们编写测试,来启动我们的spring容器类图

前言

spring有那些扩展呢?
spring的扩展非常多,比较常用的就是
BeanFactoryPostProcessor 我们可以插手spring bean工厂的初始化
BeanPostProcessor 我们可以插手spring bean实例化前后(比如SPRING AOP)
@Import
ImportAware。

BeanFactoryPostProcessor

spring的扩展点之一BeanFactoryPostProcessor,这个学名叫spring的Bean工厂后置处理器,
它可以插手spring bean工厂的实例化,我们可以启动spring的时候自己手动注册一个bean工厂后置处理器,它能做的事情太多,研究过spring源码的同学都知道,spring容器启动时候,会先暴露一个工厂出来,这个工厂就是DefaultListableBeanFactory,这里面放置了我们的BeanDeinition,我们都知道spring 单例bean容器放了很多单例的bean,而这些bean最后都是来自于DefaultListableBeanFactory中的bd容器;
BeanFactoryPostProcessor是spring提供给我们来扩展spring的,当然了它自己也在用,spring有自己内部的bean工厂后置处理器,处理的时候讲我们的和spring自己的一起处理。我们只需要把我们新建的类实现了BeanFactoryPostProcessor,并且加入@Component或者交给@Import就可以了。实现这个接口必须实现它的一个方法,它的这个方法就可以得到我们的beanDefinittionMap,也就是bdmap,这里面放置了我们系统所有的注册到spring容器里面的bd,最后spring循环这个bd,将其实例化成对象放入Bean容器。

今天我们的主题是使用sprinng的扩展点之一的@Import来实现公司的平台与spring整合,类似于Mybatis与spring整合一样

@Import

这个要说就要说很久,如果没有研究过spring底层源码的,可以去研究下,功能非常强大这边我大概介绍一下:
@import支持3中类型:
普通类(spring管理的类):就是讲一个普通的类通过@import导入,而不适用@Component,但是这样做毫无意义。
实现了ImportSelector:实现这个接口要求实现它的一个方法返回一个类名列表
Registrar:真正牛逼的注册类,实现了它,我们可以手动往里面添加自己的BeanDefiniton,自己实现扫描机制,自己实现很多很多自己的逻辑(mybatis整合spring就用的它)

实现

我的工程命名是:xxx-spring-platform-1.0.REALSE
xxx是公司的简称
工程结构:

其中context是核心,core是一些常用的核心类,aop写了一半,还没完成

POM文件

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>5.2.7.RELEASE</version>
  </dependency>
  <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.2.7.RELEASE</version>
  </dependency>
  <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-beans</artifactId>
  <version>5.2.7.RELEASE</version>
  </dependency>
  <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aop</artifactId>
  <version>5.2.7.RELEASE</version>
  </dependency>
  <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context-support</artifactId>
  <version>5.2.7.RELEASE</version>
  </dependency>

就是用了srping的几个基础包

定义数据层Resource(dao)层的扫描注解

@Documented
@Retention(RUNTIME)
@Target(TYPE)
@Import(ArteryResourceImportBeanDefinitionRegistrar.class)
//这个是用了spring的@Import
//其中用了其扩展点之一的@Import中的Registrar,ArteryResourceImportBeanDefinitionRegistrar才是我们的核心所在
public @interface ArteryResourceScan {

 String[] value() default {};

 /**
  * 基础包模式
  */
 String[] basePackages() default {};

 /**
  * 通配符的模式
  */
 String[] typeAliases() default {};

 /**
  * Artery Resource工厂Bean
  *
  * @return
  */
 Class<? extends ArteryResourceFactoryBean> factoryBean() default ArteryResourceFactoryBean.class;

 /**
  * This property specifies the annotation that the scanner will search for.
  * <p>
  * The scanner will register all interfaces in the base package that also have
  * the specified annotation
  * </p>
  */
 Class<? extends Annotation> annotationClass() default Annotation.class;

 /**
  * This property specifies the parent that the scanner will search for.
  * <p>
  * The scanner will register all interfaces in the base package that also have
  * the specified interface class as a parent.
  * </p>
  */
 Class<?> markerInterface() default Class.class;

 /**
  * The property specifies the beanName gererator will extends parent
  */

 Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

 /**
  * is lazy load,default false
  */
 boolean lazy() default false;

 /**
  * scope default singleton
  */
 String scope() default AbstractBeanDefinition.SCOPE_SINGLETON;

}

定义我的数据层Resource使用的注解

ArteryResourceImportBeanDefinitionRegistrar实现

我们的注册类实现了spring的即可ImportBeanDefinitionRegistrar,而ImportBeanDefinitionRegistrar提供了一个方法registerBeanDefinitions可以得到我们的ArteryResourceScan 注解,从而定义自己的扫描规则,使用spring的的扫描逻辑帮助我们完成扫描,然后注册到bdmap里面,因我们的Resource层是接口,而spring实例化是不能实例化接口的,所以当spring帮我们扫描成bd的时候,我们这个时候要这个扫描的列表取出来,替换我们的接口类,怎么替换呢?
因为接口需要被代理出去,而代理类帮我们完成我们想要做的事情,比如数据查询,所以我们还需要定义一个工厂bean即FactoryBean,它来帮我们产生对象,FactoryBean也是一个Bean,但是他比较特殊,它可以产生对象,我们先看Registrar的实现:

public class ArteryResourceImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

 private final String DEFAULT_RESOURACE_PATTERN = "**/*.class";

 @Override
 public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

  ClassPathArteryResourceScanner scanner = new ClassPathArteryResourceScanner(registry);
  /**
   * 拿到注解信息
   */
  AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(ArteryResourceScan.class.getName()));

  Class<? extends ArteryResourceFactoryBean> factoryBean = annoAttrs.getClass("factoryBean");
  if (!ArteryResourceFactoryBean.class.equals(factoryBean)) {
   scanner.setArteryResourceFactoryBean(BeanUtils.instantiateClass(factoryBean));
  }
  Class<? extends Annotation> annotionClass = annoAttrs.getClass("annotationClass");
  if (!Annotation.class.equals(annotionClass)) {
   scanner.setAnnotationClass(annotionClass);
  }
  Class<?> markerInteface = annoAttrs.getClass("markerInterface");
  if (!Class.class.equals(markerInteface)) {
   scanner.setMarkerInterface(markerInteface);
  }

  Class<? extends BeanNameGenerator> nameGenerator = annoAttrs.getClass("nameGenerator");
  if (!BeanNameGenerator.class.equals(nameGenerator)) {
   scanner.setBeanNameGenerator(BeanUtils.instantiateClass(nameGenerator));
  }
  scanner.setLazy(annoAttrs.getBoolean("lazy"));
  scanner.setResourceScope(annoAttrs.getString("scope"));
  //base package handler
  List<String> basePackages = new ArrayList<>(20);
  Arrays.asList(annoAttrs.getStringArray("basePackages")).forEach(item -> {
   if (StringUtils.hasText(item)) {
    basePackages.add(item);
   }
  });
  Arrays.asList(annoAttrs.getStringArray("value")).forEach(item -> {
   if (StringUtils.hasText(item)) {
    basePackages.add(item);
   }
  });

  /**
   * 处理通配符的扫描问题
   */
  String[] typeAlis = annoAttrs.getStringArray("typeAliases");
  if (typeAlis != null && typeAlis.length > 0) {
   ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
   MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver);
   //typeAliaes
   for (String typeAliases : Arrays.asList(annoAttrs.getStringArray("typeAliases"))) {
    getResource(resolver, metadataReaderFactory, typeAliases, basePackages);
   }
  }
  scanner.registerFilters();
  scanner.doScan(StringUtils.toStringArray(basePackages));
 }

 private void getResource(ResourcePatternResolver resolver, MetadataReaderFactory metadataReaderFactory, String classPath, List<String> basePackages) {
  classPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(classPath) + "/" + DEFAULT_RESOURACE_PATTERN;
  try {
   Resource[] resources = resolver.getResources(classPath);
   if (resources != null && resources.length > 0) {
    MetadataReader metadataReader = null;
    for (Resource resource : resources) {
     if (resource.isReadable()) {
      metadataReader = metadataReaderFactory.getMetadataReader(resource);
      basePackages.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName());
     }
    }
   }
  } catch (IOException | ClassNotFoundException e) {
   e.printStackTrace();
  }
 }
}

以上代码的doScan方法是核心,是调用了我们自定义的扫描类

自定义扫描类ClassPathArteryResourceScanner

public class ClassPathArteryResourceScanner extends ClassPathBeanDefinitionScanner {
 private final Logger logger = LoggerFactory.getLogger(ClassPathArteryResourceScanner.class);
 /**
  * factory baen instance
  */
 private ArteryResourceFactoryBean<?> arteryResourceFactoryBean = new ArteryResourceFactoryBean<Object>();
 /**
  * scanner class
  */
 private Class<? extends Annotation> annotationClass;
 /**
  * scanner class
  */
 private Class<?> markerInterface;
 /**
  * is lazy load ,default false
  */
 private boolean isLazy = false;
 /**
  * scope is cantains singleton and prototype,default singlton
  */
 private String resourceScope = AbstractBeanDefinition.SCOPE_SINGLETON;

 /**
  * 调用父类的构造,构造出扫描对象
  *
  * @param registry
  */
 public ClassPathArteryResourceScanner(BeanDefinitionRegistry registry) {
  super(registry, false);
 }

 public void registerFilters() {
  //是否允许所有的所有的接口(预留)
  boolean acceptAllIntefaces = true;

  if (this.annotationClass != null) {
   addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
   acceptAllIntefaces = false;
  }
  if (this.markerInterface != null) {
   addIncludeFilter(new AssignableTypeFilter(this.markerInterface));
   acceptAllIntefaces = false;
  }
  if (acceptAllIntefaces) {
   addIncludeFilter(new TypeFilter() {
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
     return true;
    }
   });
  }

 }

 @Override
 public Set<BeanDefinitionHolder> doScan(String... basePackages) {

  Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
  if (!beanDefinitions.isEmpty()) {
   //SPRING 扫描到每个加了@Component或者@Service 成BD
   processBeanDefinitions(beanDefinitions);
  }
  return beanDefinitions;
 }

 private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
  beanDefinitions.forEach(this::processBeanDefinition);
 }

 private void processBeanDefinition(BeanDefinitionHolder holder) {
  GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();
  if (logger.isDebugEnabled()) {
   logger.debug("Creating ArteryResourceBean with name {} and {} mapperInterfaces", holder.getBeanName(), definition.getBeanClassName());
  }
  definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());
  definition.setBeanClass(this.arteryResourceFactoryBean.getClass());
  definition.setLazyInit(isLazy);//延迟加载
  definition.setScope(resourceScope);
  definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
 }

 @Override
 protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
  // check is sucess
  boolean isSucc = true;
  if (super.checkCandidate(beanName, beanDefinition)) {
   isSucc = true;
  } else {
   isSucc = false;
  }
  return isSucc;
 }

 @Override
 protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
  boolean isComponent = false;
  String beanClassName = beanDefinition.getMetadata().getClassName();
  isComponent = beanClassName.endsWith("Resource");
  try {

   isComponent = isComponent ? Class.forName(beanDefinition.getMetadata().getClassName()).isAnnotationPresent(ArteryDao.class) : false;
  } catch (ClassNotFoundException e) {
   e.printStackTrace();
  }
  if (isComponent) {
   isComponent = beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
  }
  return isComponent;
 }

 public void setArteryResourceFactoryBean(ArteryResourceFactoryBean<?> arteryResourceFactoryBean) {
  this.arteryResourceFactoryBean = arteryResourceFactoryBean;
 }

 public void setAnnotationClass(Class<? extends Annotation> annotationClass) {
  this.annotationClass = annotationClass;
 }

 public void setLazy(boolean lazy) {
  isLazy = lazy;
 }

 public void setResourceScope(String resourceScope) {
  this.resourceScope = resourceScope;
 }

 public void setMarkerInterface(Class<?> markerInterface) {
  this.markerInterface = markerInterface;
 }
}

processBeanDefinition这个方法里面就拿到spring给我们扫描返回的bd,我们循环这个bd
然后替换我们的Resource接口,这里用的是一个FactoryBean
而这个工厂Bean里面的getObject是返回了一个代理对象,具体看下面代码:

代理注册工厂ResourceRegistry

它的作用主要是来管理我们的注册工厂

Resouce的代理工厂

它来管理我们的Resouce工厂,从这个Resource工厂中产生代理类,也就是我们的代理类都在代理工厂中产生,然后我们调用的时候是通过它来产生的一个proxy

真正的代理类

public class ResourceProxy<T> implements InvocationHandler, Serializable {
 private static final long serialVersionUID = 1L;
 private final Logger logger = LoggerFactory.getLogger(ResourceProxy.class);

 private final Class<T> resourceInterface;
 private final Map<Method, ResourceMethod> cacheMethod;

 public ResourceProxy(Class<T> resourceInterface, Map<Method, ResourceMethod> cacheMethod) {
  this.resourceInterface = resourceInterface;
  this.cacheMethod = cacheMethod;
 }

 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  Object result = null;
  /**
   * handler tostring method
   */
  if (Object.class.equals(method.getDeclaringClass())) {
   result = method.invoke(this, args);
  } else if (isDefaultMethod(method)) {
   result = invokeDefaultMethod(proxy, method, args);
  } else {
   /**
    * user invoke handler
    */
   if (logger.isDebugEnabled()) {
    logger.debug("ResourceProxy.invoke begin ....");
    logger.debug("================================================");
    logger.debug("invoke interface name={}", proxy.getClass().getInterfaces()[0].getName());
    logger.debug("invoke method name={}", method.getName());
    logger.debug("invoke method args={}", args);
   }
   ResourceMethod resourceMethod = getCacheMethod(method);
   result = resourceMethod.execute(args);
   if (logger.isDebugEnabled()) {
    logger.debug("ResourceProxy.invoke end ....");
    logger.debug("================================================");
    logger.debug("invoke method result={}", result);
   }
  }
  return result;
 }

 public ResourceMethod getCacheMethod(Method method) {
  ResourceMethod resourceMethod = cacheMethod.get(method);
  if (resourceMethod == null) {
   resourceMethod = new ResourceMethod(method, resourceInterface);
   cacheMethod.put(method, resourceMethod);
  }
  return resourceMethod;
 }

 /**
  * invoke default method
  *
  * @param proxy proxy object
  * @param method proxy invoke method
  * @param args method args
  * @return
  * @throws Throwable
  */
 private Object invokeDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable {
  final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
  if (!constructor.isAccessible()) {
   constructor.setAccessible(true);
  }
  final Class<?> declaringClass = method.getDeclaringClass();
  return constructor.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE)
    .unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
 }

 /**
  * check is default method
  *
  * @param method
  * @return
  */
 private boolean isDefaultMethod(Method method) {
  return ((method.getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC) && method.getDeclaringClass().isInterface();
 }
}

方法调用类

public class ResourceMethod<T> extends AbstractAnnotaionHandlerResource<T> {

 private final Method method;

 private final Class<?> resourceInterface;

 public ResourceMethod(Method method, Class<?> resourceInterface) {
  this.method = method;
  this.resourceInterface = resourceInterface;
 }

 public Object execute(Object[] args) throws Exception {
  Object result = null;
  initTemplate();
  if (method.isAnnotationPresent(PubHandler.class)) {
   result = pubHandler(args);
  } else {
   result = invokeExtMethod(args);
  }
  return result;
 }

 private void initTemplate(){
  if(queryTemplate == null){
   queryTemplate = SpringContainerApplicationContext.getInstance().getBean("queryTemplate");
  }

  if(updateTemplate == null){
   updateTemplate =SpringContainerApplicationContext.getInstance().getBean("updateTemplate");

  }
 }

 private Object invokeExtMethod(Object[] args) throws Exception {
  Object result = null;
  Annotation[] annotations = method.getAnnotations();
  if (annotations != null && annotations.length > 0) {
   String annotationName = annotations[0].annotationType().getSimpleName();
   SqlCommandType type = SqlCommandType.valueOf(annotationName);
   switch (type) {
    case SELECT:
     result = executeQuery(method.getAnnotation(SELECT.class), args);
     break;
    case INSERT:
     result = executeInsert(method.getAnnotation(INSERT.class), args);
     break;
    case DELETE:
     result = executeDelete(method.getAnnotation(DELETE.class), args);
     break;
    case UPDATE:
     result = executeUpdate(method.getAnnotation(UPDATE.class), args);
     break;
   }
  }
  return result;
 }

 private Object pubHandler(Object[] args) {
  Object result = null;
  PubHandler ph = method.getAnnotation(PubHandler.class);
  switch (ph.handlerType()) {
   case P_Q_PAGING:
    result = P_Q_PAGING(args);
    break;
   case L_Q_PAGING:
    result = L_Q_PAGING(args);
    break;
   case I_PERSISTENCE_IN:
    result = I_PERSISTENCE_IN(args);
    break;
   case I_PERSISTENCE_UP:
    result = I_PERSISTENCE_UP(args);
    break;
   case I_PERSISTENCE_UP_OVERRIDE:
    result = I_PERSISTENCE_UP_OVERRIDE(args);
    break;
   case I_PSERSISTENCE_DE:
    result = I_PSERSISTENCE_DE(args);
    break;
   case I_PSERSISTENCE_DE_OVERRIDE:
    result = I_PSERSISTENCE_DE_OVERRIDE(args);
    break;
   case E_Q_GET:
    result = E_Q_GET(args);
    break;
   case L_Q_ENTITY:
    result = L_Q_ENTITY(args);
    break;
   case L_Q_ENTITY_OVERRIDE:
    result = L_Q_ENTITY_OVERRIDE(args);
    break;
   case I_BATCH_PERSISTENCE:
    result = I_BATCH_PERSISTENCE(args);
    break;
   case I_COUNT:
    result = I_COUNT(args);
    break;
  }
  return result;
 }
 @Override
 public Method getMethod() {
  return method;
 }

 @Override
 public Class<?> targetInterface() {
  return resourceInterface;
 }

从第七步调用直接到了这里,其中1和2是不一样的,哪里不一样呢?因为pubHandler是我们在基类里面封装的curd操作,如果是调用基类,那么会直接将请求代理给我的基类去做,如果是通过注解sql的那么就执行invokeExtMethod


最后我们编写一个工厂来获取我们的Bean

AbstractBeanDefinitionFactory

public abstract class AbstractBeanDefinitionFactory extends AnnotationConfigDefinitionApplicationContext
		implements BeanDefinitionFactory {

	@SuppressWarnings("unchecked")
	@Override
	public <K> K getBean(String beanName) {
		check();
		DefinitionBeanFactory<K> beanfactory = () -> {
			Object beanInstance = super.applicationContxt.getBean(beanName);
			if (beanInstance != null) {
				return (K) beanInstance;
			} else {
				throw new RuntimeException(" get spring ioc instance is null ");
			}
		};
		return beanfactory.getBeanObject();
	}

	@Override
	public <K> K getBean(Class<K> kclzz) {
		check();
		DefinitionBeanFactory<K> beanfactory = () -> super.applicationContxt.getBean(kclzz);
		return beanfactory.getBeanObject();
	}

	private void check() {
		if(!super.runStatus) {
			throw new RuntimeException("spring 容器未运行");
		}
	}

	@Override
	public <K> K getBean(String beanName, Class<K> kClass) {
		check();
		DefinitionBeanFactory<K> beanFactory = () -> super.applicationContxt.getBean(beanName,kClass);
		return null;
	}
}

我们编写测试,来启动我们的spring容器


以上我只是提供了一个spring扩展的思路,上面截图和代码都不全,因为涉及到公司机密性,我没有办法暴露太多东西在上面,所以有兴趣可以一起交流交流;整合spring的这个框架是我自己编写,没有任何人参与进来,所以我希望如果有这方面兴趣的朋友可以一起交流交流

类图

我的启动类的之间关系(全部是自己的类,不是spring的类):

代理工厂调用的调用的方法处理继承关系:

最后预祝我的两个小公主一直开心快乐,身体永远健康,爸爸永远爱你们。

到此这篇关于如何利用Spring的@Import扩展点与spring进行无缝整合的文章就介绍到这了,更多相关Spring的@Import扩展点与spring无缝整合内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解SpringBoot开发使用@ImportResource注解影响拦截器

    问题描述 今天在给SpringBoot项目配置拦截器的时候发现怎么都进不到拦截器的方法里面,在搜索引擎上看了无数篇关于配置拦截器的文章都没有找到解决方案. 就在我准备放弃的时候,在 CSDN 上发现了一篇文章,说的是SpringBoot 用了@ImportResource 配置的拦截器就不起作用了.于是我就赶紧到Application启动类看了一眼,果然项目中使用了@ImportResource 注解用于配置系统的参数. 代码如下: 启动类配置 package com.xx.xxx; impor

  • Springboot @Import 详解

    SpringBoot 的 @Import 用于将指定的类实例注入之Spring IOC Container中. 今天抽空在仔细看了下Springboot 关于 @Import 的处理过程, 记下来以后看. 1. @Import 先看Spring对它的注释 (文档贴过来的), 总结下来作用就是和xml配置的 <import />标签作用一样,允许通过它引入 @Configuration 注解的类 (java config), 引入ImportSelector接口(这个比较重要, 因为要通过它去判

  • Spring中@Import的各种用法以及ImportAware接口详解

    @Import 注解 @Import注解提供了和XML中<import/>元素等价的功能,实现导入的一个或多个配置类.@Import即可以在类上使用,也可以作为元注解使用. @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Import { /** * {@link Configuration}, {@link ImportSelector}, {@link I

  • Spring Boot和Kotlin的无缝整合与完美交融

    前言 本文讲解 Spring Boot2 基础下,如何使用 Kotlin,并无缝整合与完美交融.为了让读者更加熟悉 Kotlin 的语法糖,笔者会在未来的几篇文章中,聊聊 Kotlin 的新特性及其语法糖.下面话不多说了,来一起看看详细的介绍吧 环境依赖 修改 POM 文件,添加 spring boot 依赖. <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-bo

  • spring注解@Import用法详解

    [1]@Import 参数value接收一个Class数组,将你传入的类以全类名作为id加入IOC容器中 ​比较简单,此处不做详细解释 [2]ImportSelector ImportSelector强调的是复用性,使用它需要创建一个类实现ImportSelector接口,实现方法的返回值是字符串数组,也就是需要注入容器中的组件的全类名.id同样也是全类名. ​ 上代码: //自定义逻辑返回需要导入的组件 public class MyImportSelector implements Impo

  • 如何利用Spring的@Import扩展点与spring进行无缝整合

    利用Spring的@Import扩展与spring进行无缝整合前言BeanFactoryPostProcessor@Import实现POM文件定义数据层Resource(dao)层的扫描注解定义我的数据层Resource使用的注解ArteryResourceImportBeanDefinitionRegistrar实现自定义扫描类ClassPathArteryResourceScanner代理注册工厂ResourceRegistryResouce的代理工厂真正的代理类方法调用类AbstractB

  • Dubbo扩展点SPI实践示例解析

    目录 正文 扩展点配置: 扩展实现类: 拦截配置文件: 调用拦截扩展: 拦截扩展说明: 常用约定: 实现细节: 扩展点的几个特点: 扩展点自动包装 扩展点自动装配 扩展点自适应 扩展点自动激活 正文 Dubbo的扩展点加载从JDK标准的SPI(Service Provider Interface)扩展点发现机制加强而来.Dubbo改进了JDK标准的SPI的以下问题: JDK标准的SPI会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源.如果扩展点加载失败,

  • SpringBoot扩展点EnvironmentPostProcessor实例详解

    目录 一.背景 二.需求 三.分析 1.什么时候向SpringBoot中加入我们自己的配置属性 2.获取配置属性的优先级 3.何时加入我们自己的配置 四.实现 1.引入SpringBoot依赖 2.在application.properties中配置属性 3.编写自定义属性并加入Spring Environment中 4.通过SPI使自定义的配置生效 5.编写测试类,输出定义的 username 属性的值 6.运行结果 五.注意事项 1.日志无法输出 3.日志系统如何初始化 六.完整代码 七.参

  • 浅谈Spring中@Import注解的作用和使用

    @Import用来导入@Configuration注解的配置类.声明@Bean注解的bean方法.导入ImportSelector的实现类或导入ImportBeanDefinitionRegistrar的实现类. @Import注解的作用 查看Import注解源码 /** * Indicates one or more {@link Configuration @Configuration} classes to import. * * <p>Provides functionality eq

  • Spring通过<import>标签导入外部配置文件

    示例 我们先来看下配置文件是怎么导入外部配置文件的?先定义一个spring-import配置文件如下: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xs

  • SpringBoot使用spring.config.import多种方式导入配置文件

    目录 简介 导入classpath下的配置文件 导入系统目录下的配置文件 导入Nacos配置中心的配置文件 总结 简介 SpringBoot从2.4.x版本开始支持了导入文件的方式来加载配置参数,与spring.config.additional-location不同的是不用提前设置而且支持导入的文件类型相对来说要丰富很多. 我们只需要在application.properties/application.yml配置文件中通过spring.config.import属性配置需要导入的文件列表即可

  • Spring注解@Import原理解析

    目录 正文 @Import 原理 示例 @EnableAsync 正文 在项目开发的过程中,我们会遇到很多名字为 @Enablexxx 的注解,比如@EnableApolloConfig. @EnableFeignClients. @EnableAsync 等.他们的功能都是通过这样的注解实现一个开关,决定了是否开启某个功能模块的所有组件的自动化配置,这极大的降低了我们的使用成本. 那么你是好奇过 @Enablexxx 是如何达到这种效果呢,其作用机制是怎么样的呢? @Import 原理 按照默

  • spring学习之创建项目 Hello Spring实例代码

    本文研究的主要是spring学习之创建项目 Hello Spring实例代码,具体如下. 一.创建eclipse项目,引入jar包 1.eclipse创建java project项目 HelloSpring 2.创建lib目录,加入spring必须的5个jar包 3.选中5个文件,右键 -> Build Path -> add to build path 二.编写spring的hello spring代码 1.创建包io.spring.beans,并编写HelloWorld.java pack

  • Spring实战之让Bean获取Spring容器操作示例

    本文实例讲述了Spring实战之让Bean获取Spring容器操作.分享给大家供大家参考,具体如下: 一 配置 <?xml version="1.0" encoding="GBK"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans"

随机推荐