欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

如何利用Spring的@Import擴展點與spring進行無縫整合

 更新時間:2020年08月08日 15:35:40   作者:scjava  
這篇文章主要介紹了如何利用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循環(huán)這個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使用的注解

為了規(guī)范過濾我們的數據接口層

ArteryResourceImportBeanDefinitionRegistrar實現

我們的注冊類實現了spring的即可ImportBeanDefinitionRegistrar,而ImportBeanDefinitionRegistrar提供了一個方法registerBeanDefinitions可以得到我們的ArteryResourceScan 注解,從而定義自己的掃描規(guī)則,使用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,我們循環(huán)這個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的那么就執(zhí)行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無縫整合內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 使用java采集京東商城區(qū)劃數據示例

    使用java采集京東商城區(qū)劃數據示例

    這篇文章主要介紹了java采集京東的全國區(qū)劃數據示例,保存成json形式,如想轉換到數據庫只需反序列化為對象保存到數據庫即可
    2014-03-03
  • Java LinkedList集合功能實例解析

    Java LinkedList集合功能實例解析

    這篇文章主要介紹了Java LinkedList集合功能實例解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-04-04
  • java接口語法以及與類的關系詳解

    java接口語法以及與類的關系詳解

    接口在JAVA編程語言中是一個抽象類型,是抽象方法的集合,接口通常以interface來聲明。一個類通過繼承接口的方式,從而來繼承接口的抽象方法
    2021-10-10
  • java多態(tài)實現電子寵物系統

    java多態(tài)實現電子寵物系統

    這篇文章主要為大家詳細介紹了java多態(tài)實現電子寵物系統,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • Java動態(tài)規(guī)劃之丑數問題實例講解

    Java動態(tài)規(guī)劃之丑數問題實例講解

    這篇文章主要介紹了Java動態(tài)規(guī)劃之丑數問題實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧
    2022-09-09
  • idea2020安裝MybatisCodeHelper插件的圖文教程

    idea2020安裝MybatisCodeHelper插件的圖文教程

    這篇文章主要介紹了idea2020安裝MybatisCodeHelper插件的方法,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-09-09
  • 深入理解Java 線程通信

    深入理解Java 線程通信

    這篇文章主要介紹了Java 線程通信的的相關資料,文中講解非常細致,代碼幫助大家更好的理解和學習,感興趣的朋友可以了解下
    2020-06-06
  • 如何在Java中優(yōu)雅地判空詳解

    如何在Java中優(yōu)雅地判空詳解

    這篇文章主要大家介紹了關于如何在Java中優(yōu)雅地判空的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-11-11
  • intellij idea設置統一JavaDoc模板的方法詳解

    intellij idea設置統一JavaDoc模板的方法詳解

    這篇文章主要介紹了intellij idea設置統一JavaDoc模板的方法詳解,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • SpringCloud邁向云原生的步驟

    SpringCloud邁向云原生的步驟

    這篇文章主要介紹了SpringCloud怎么邁向云原生,通過本文我們來梳理一下Spring?Cloud的前世今生,以及未來云原生發(fā)展的趨勢,可以給這些RPC框架的演進帶來一些啟發(fā),感興趣的朋友跟隨小編一起看看吧
    2022-10-10

最新評論