在.net core中实现字段和属性注入的示例代码

简单来说,使用Ioc模式需要两个步骤,第一是把服务注册到容器中,第二是从容器中获取服务,我们一个一个讨论并演化。这里不会考虑使用如Autofac等第三方的容器来代替默认容器,只是提供一些简单实用的小方法用于简化应用层的开发。

将服务注入到容器

asp.netcore官方给出的在容器中注册服务方法是,要在Startup类的ConfigureServices方法中添加服务,如下所示:

public void ConfigureServices(IServiceCollection services)
{
  services.AddMvc();

  services.AddSingleton(typeof(UserService));
  services.AddSingleton(typeof(MsgService));
  services.AddSingleton(typeof(OrderService));
}

AddMvc方法添加了mvc模块内部用到的一些服务,这个是封装好的,一句话就行了,其他第三方组件也都提供了类似的Add方法,把自己内部需要的服务都封装好注册进去了。但是我们应用开发人员使用的类,还是需要一个一个写进去的,大家最常见的三层架构中的数据访问层和业务逻辑层便是此类服务,上面代码中我加入了三个业务服务类。这显然不是长久之计,我想大家在开发中也会针对此问题做一些处理,这里说下我的,仅供参考吧。

解决方法就是批量注册!说到批量,就需要一个东西来标识一批东西,然后用这一个东西来控制这一批东西。在.net程序的世界中,有两个可选的角色,一个是接口Interface,另一个是特性Attribute。

如果使用接口作为标识来使用,限制就太死板了,一个标识的信息不是绝对的单一,是不推荐使用接口的,因为可能需要引入多个接口才能共同完成,所以我选择特性作为标识。特性相较与接口有什么特点呢?特性在运行时是类的实例,所以可以存储更多的信息。

下面我们简单实现一个AppServiceAttribute:

/// <summary>
/// 标记服务
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class AppServiceAttribute : Attribute
{
}

这个特性类取名AppService有两个理由,一是指定是应用层的服务类,二是避免使用Service这样的通用命名和其他类库冲突。

有了标识,就可以批量处理了,我们在一个新的类中给IServiceCollection提供一个扩展方法,用来批量添加标记有AppService特性的服务到容器中。

public static class AppServiceExtensions
{
  /// <summary>
  /// 注册应用程序域中所有有AppService特性的服务
  /// </summary>
  /// <param name="services"></param>
  public static void AddAppServices(this IServiceCollection services)
  {
    foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
    {
      foreach (var type in assembly.GetTypes())
      {
        var serviceAttribute = type.GetCustomAttribute<AppServiceAttribute>();

        if (serviceAttribute != null)
        {
          services.AddSingleton(type);
        }
      }
    }
  }
}

我们遍历应用程序中所有程序集,然后嵌套遍历每个程序集中的所有类型,判断类型是否有AppService特性,如果有的话就添加到容器中,这里有点不自信哦,为什么呢,因为我是使用AddSingleton方法以单例模式将服务添加到容器中的,虽然三层中的数据访问层和业务逻辑层绝大部分都可以使用单例,但是我们希望更通用一些,大家都知道netcore自带的Ioc容器支持三种生命周期,所以我们修改AppServiceAttribute,添加一个Lifetime属性:

[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class AppServiceAttribute : Attribute
{
  /// <summary>
  /// 生命周期
  /// </summary>
  public ServiceLifetime Lifetime { get; set; } = ServiceLifetime.Singleton;
}

Lifetime的默认值我们设置成ServiceLifetime.Singleton是比较合适的,因为大部分服务我们都希望使用单例注册,一个合理的默认设置可以节省使用者很多代码,新手可能还会乐于复制粘贴,但老同志肯定都深有体会。

有了Lifetime这个信息,我们就可以改进AddAppServices方法了,在判断serviceAttribute不为null后,使用下面的代码替换services.AddSingleton(type):

  switch (serviceAttribute.Lifetime)
  {
    case ServiceLifetime.Singleton:
      services.AddSingleton(serviceType, type);
      break;
    case ServiceLifetime.Scoped:
      services.AddScoped(serviceType, type);
      break;
    case ServiceLifetime.Transient:
      services.AddTransient(serviceType, type);
      break;
    default:
      break;
  }

现在我们可以注册不同生命周期的服务了,只是该控制是在类的定义中,按理说,服务对象注册到容器中的生命周期,是不应该在类的定义中确定的,因为一个类的定义是独立的,定义好之后,使用者可以用任何一种容器支持的生命周期来注册实例。但是此时这样的设计是比较合理的,因为我们要解决的是应用层服务的批量注册,这类服务一般在定义的时候就已经确定了使用方式,而且很多时候服务的开发者就是该服务的使用者!所以我们可以把这个当成合理的反范式设计。

目前这样子,对于我来说,基本已经够用了,因为在应用层,我都是依赖实现编程的😀(哈哈,会不会很多人说咦......呢?)。设计模式说:“要依赖于抽象,不要依赖于具体”,这点我还没做到,我抽空检讨(呵呵,谁信呢!)。所以呢,我们的批量注入要支持那些优秀的同学。

从上面的代码不难发现,如果定义接口IA和其实现A:IA,并在A上添加AppService特性是不行的:

  public interface IA { }

  [AppService]
  public class A : IA { }

这个时候我们并不能依赖IA编程,因为我们注册的服务类是A,实现类是A,我们需要注册成服务类是IA,实现类是A才可:

public class HomeController : Controller
{
  private IA a;
  public HomeController(IA a)
  {
    this.a = a; //这里a是null,不能使用
  }
}

让我继续改进,在AppServiceAttribute中,我们加入服务类型的信息:

[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class AppServiceAttribute : Attribute
{
  /// <summary>
  /// 生命周期
  /// </summary>
  public ServiceLifetime Lifetime { get; set; } = ServiceLifetime.Singleton;
  /// <summary>
  /// 指定服务类型
  /// </summary>
  public Type ServiceType { get; set; }
  /// <summary>
  /// 是否可以从第一个接口获取服务类型
  /// </summary>
  public bool InterfaceServiceType { get; set; } = true;
}

我们从两个方面入手来解决服务类型的问题,一个是指定ServiceType,这个就毫无疑问了,在A的AppService中可以明确指定IA为其服务类:

[AppService(ServiceType = typeof(IA))]
public class A : IA { }

另一个是从服务类自身所继承的接口中获取服务类形,这一点要在AddAppServices方法中体现了,再次改进AddAppServices方法,还是替换最开始services.AddSingleton(type)的位置:

  var serviceType = serviceAttribute.ServiceType;
  if (serviceType == null && serviceAttribute.InterfaceServiceType)
  {
    serviceType = type.GetInterfaces().FirstOrDefault();
  }
  if (serviceType == null)
  {
    serviceType = type;
  }
  switch (serviceAttribute.Lifetime)
  {
    case ServiceLifetime.Singleton:
      services.AddSingleton(serviceType, type);
      break;
    case ServiceLifetime.Scoped:
      services.AddScoped(serviceType, type);
      break;
    case ServiceLifetime.Transient:
      services.AddTransient(serviceType, type);
      break;
    default:
      break;
  }

我们首先检查serviceAttribute.ServiceType,如果有值的话,它就是注册服务的类型,如果没有的话,看是否允许从接口中获取服务类型,如果允许,便尝试获取第一个作为服务类型,如果还没获取到,就把自身的类型作为服务类型。

  • 第一种情况不常见,特殊情况才会指定ServiceType,因为写起来麻烦;
  • 第二种情况适用于依赖抽象编程的同学,注意这里只取第一个接口的类型;
  • 第三种情况就是适用于像我这种有不良习惯的患者(依赖实现编程)!

到此为止我们的服务注册已经讨论完了,下面看看如何获取。

字段和属性注入

这里我们说的获取,不是框架默认容器提供的构造器注入,而是要实现字段和属性注入,先看看构造器注入是什么样的:

public class HomeController : Controller
{
  UserService userService;
  OrderService orderService;
  MsgService msgService;
  OtherService otherService;
  OtherService2 otherService2;

  public HomeController(UserService userService, OrderService orderService, MsgService msgService, OtherService otherService, OtherService2 otherService2)
  {
    this.userService = userService;
    this.orderService = orderService;
    this.msgService = msgService;
    this.otherService = otherService;
    this.otherService2 = otherService2;
  }
}

如果引用的服务不再添加还好,如果编写边添加就太要命了,每次都要定义字段、在构造器方法签名中些添加参数、在构造器中赋值,便捷性和Spring的@autowired注解没法比,所以我们要虚心学习,创作更便捷的操作。
首先我们再定义个特性,叫AutowiredAttribute,虽然也是个标识,但是由于这个特性是用在字段或者属性上,所以只能用特性Attribute,而不能使用接口Interface,到这里我们又发现一点,使用接口作为标识的话,只能用在类、接口和结构中,而不能用在他们的成员上,毕竟接口的主要作用是定义一组方法契约(即抽象)!

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class AutowiredAttribute : Attribute
{
}

这个特性里面什么也没有,主要是下面这个类,装配操作都在这里:

/// <summary>
/// 从容器装配service
/// </summary>
[AppService]
public class AutowiredService
{
  IServiceProvider serviceProvider;
  public AutowiredService(IServiceProvider serviceProvider)
  {
    this.serviceProvider = serviceProvider;
  }
  public void Autowired(object service)
  {
    var serviceType = service.GetType();
    //字段赋值
    foreach (FieldInfo field in serviceType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
    {
      var autowiredAttr = field.GetCustomAttribute<AutowiredAttribute>();
      if (autowiredAttr != null)
      {
        field.SetValue(service, serviceProvider.GetService(field.FieldType));
      }
    }
    //属性赋值
    foreach (PropertyInfo property in serviceType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
    {
      var autowiredAttr = property.GetCustomAttribute<AutowiredAttribute>();
      if (autowiredAttr != null)
      {
        property.SetValue(service, serviceProvider.GetService(property.PropertyType));
      }
    }
  }
}

我们刚刚写的[AppService]特性在这里已经用上了,并且这个类使用构造器注入了IServiceProvider。Autowired(object service)方法的参数是要装配的服务实例,首先获取服务类型,再使用反射查询有AutowiredAttribute特性的字段和属性,我们在构造器注入了serviceProvider,这里便可以使用serviceProvider的GetService方法从容器中获取对应类型的实例来给字段和属性赋值。 整个过程就是这样,简单明了。开始的时候我想使用静态类来编写AutowiredService,但是静态类没法注入IServiceProvider,解决方法也有,可以使用定位器模式全局保存IServiceProvider:

/// <summary>
/// 服务提供者定位器
/// </summary>
public static class ServiceLocator
{
  public static IServiceProvider Instance { get; set; }
}

在Setup的Configure方法中赋值:

ServiceLocator.Instance = app.ApplicationServices;

这样在静态的AutowiredService中也就可以访问IServiceProvider了,但是使其自己也注册成服务能更好的和其他组件交互,java有了spring框架,大家都认可spring,一切都在容器中,一切都可注入,spring提供了统一的对象管理,非常好,我感觉netcore的将来也将会是这样。

Autowired(object service)方法的实现虽然简单,但是使用了效率底下的反射,这个美中不足需要改进,以前可以使用晦涩难懂的EMIT来编写,现在有Expression,编写和阅读都简单了好多,并且效率也不比EMIT差,所以我们使用表达式+缓存来改进。Autowired方法要做的就是从容器中取出合适的对象,然后赋值给service要自动装配的字段和属性,据此我们先编写出委托的伪代码:

(obj,serviceProvider)=>{
  ((TService)obj).aa=(TAAType)serviceProvider.GetService(aaFieldType);
  ((TService)obj).bb=(TBBType)serviceProvider.GetService(aaFieldType);
  ...
}

注意伪代码中的类型转换,Expression表达式在编译成委托时是非常严格的,所有转换都不能省。写表达式的时候我习惯先写伪代码,我希望大家也能养成这个习惯!有了伪代码我们可以开始改造AutowiredService类了:

  /// <summary>
  /// 从容器装配service
  /// </summary>
  [AppService]
  public class AutowiredService
  {
    IServiceProvider serviceProvider;
    public AutowiredService(IServiceProvider serviceProvider)
    {
      this.serviceProvider = serviceProvider;
    }

    Dictionary<Type, Action<object, IServiceProvider>> autowiredActions = new Dictionary<Type, Action<object, IServiceProvider>>();

    public void Autowired(object service)
    {
      Autowired(service, serviceProvider);
    }
    /// <summary>
    /// 装配属性和字段
    /// </summary>
    /// <param name="service"></param>
    /// <param name="serviceProvider"></param>
    public void Autowired(object service, IServiceProvider serviceProvider)
    {
      var serviceType = service.GetType();
      if (autowiredActions.TryGetValue(serviceType, out Action<object, IServiceProvider> act))
      {
        act(service, serviceProvider);
      }
      else
      {
        //参数
        var objParam = Expression.Parameter(typeof(object), "obj");
        var spParam = Expression.Parameter(typeof(IServiceProvider), "sp");

        var obj = Expression.Convert(objParam, serviceType);
        var GetService = typeof(IServiceProvider).GetMethod("GetService");
        List<Expression> setList = new List<Expression>();

        //字段赋值
        foreach (FieldInfo field in serviceType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
        {
          var autowiredAttr = field.GetCustomAttribute<AutowiredAttribute>();
          if (autowiredAttr != null)
          {
            var fieldExp = Expression.Field(obj, field);
            var createService = Expression.Call(spParam, GetService, Expression.Constant(field.FieldType));
            var setExp = Expression.Assign(fieldExp, Expression.Convert(createService, field.FieldType));
            setList.Add(setExp);
          }
        }
        //属性赋值
        foreach (PropertyInfo property in serviceType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
        {
          var autowiredAttr = property.GetCustomAttribute<AutowiredAttribute>();
          if (autowiredAttr != null)
          {
            var propExp = Expression.Property(obj, property);
            var createService = Expression.Call(spParam, GetService, Expression.Constant(property.PropertyType));
            var setExp = Expression.Assign(propExp, Expression.Convert(createService, property.PropertyType));
            setList.Add(setExp);
          }
        }
        var bodyExp = Expression.Block(setList);
        var setAction = Expression.Lambda<Action<object, IServiceProvider>>(bodyExp, objParam, spParam).Compile();
        autowiredActions[serviceType] = setAction;
        setAction(service, serviceProvider);
      }
    }
  }

代码一下子多了不少,不过由于我们前面的铺垫,理解起来也不难,至此自动装配字段和属性的服务已经写好了,下面看看如何使用:

编写服务类,并添加[AppService]特性

[AppService]
public class MyService
{
  //functions
}

在Setup的ConfigureServices方法中注册应用服务

public void ConfigureServices(IServiceCollection services)
{
  services.AddMvc();
  //注册应用服务
  services.AddAppServices();
}

在其他类中注入使用,比如Controller中

public class HomeController : Controller
{
  [Autowired]
  MyUserService myUserService;

  public HomeController(AutowiredService autowiredService)
  {
    autowiredService.Autowired(this);
  }
}

HomeController的构造函数是不是简洁了许多呢!而且再有新的服务要注入,只要定义字段(属性也可以,不过字段更方便)就可以了,注意:我们定义的字段不能是只读的,因为我们要在AutowiredService中设置。我们还用上面的例子,看一下它的威力吧!

public class HomeController : Controller
{
  [Autowired]
  UserService userService;
  [Autowired]
  OrderService orderService;
  [Autowired]
  MsgService msgService;
  [Autowired]
  OtherService otherService;
  [Autowired]
  OtherService2 otherService2;

  public HomeController(AutowiredService autowiredService)
  {
    autowiredService.Autowired(this);
  }
}

感谢您的观看!全文已经完了,我们没有使用第三方容器,也没有对自带的容器大肆修改和破坏,只是在服务类的构造器中选择性的调用了AutowiredService.Autowired(this)方法,为什么是选择性的呢,因为你还可以使用在构造器中注入的方式,甚至混用,一切都好,都不会错乱。

nuget安装:

PM> Install-Package Autowired.Core

git源码:

[Autowired.Core] https://gitee.com/loogn/Autowired.Core

更新:

  • 支持多个AppServiceAttribute,
  • 支持服务唯一标识,通过Identifier指定服务实现

到此这篇关于在.net core中实现字段和属性注入的示例代码的文章就介绍到这了,更多相关.net core 字段和属性注入内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • ASP.NET Core 奇淫技巧之伪属性注入的实现

    一.前言 开局先唠嗑一下,许久未曾更新博客,一直在调整自己的状态,去年是我的本命年,或许是应验了本命年的多灾多难,过得十分不顺,不论是生活上还是工作上.还好当我度过了所谓的本命年后,许多事情都在慢慢变好,我将会开始恢复更新博客,争取恢复到以前的速度上(因为工作比较忙,所以这个过程可能需要一段时间). 二.关于属性注入 说到属性注入,我们就不得不提一下 DI(Dependency Injection),即依赖注入,用过 ASP.NET Core 的同学相信对这个词不会陌生.ASP.NET Core

  • .Net Core在程序的任意位置使用和注入服务的方法

    最近有人问我:我该如何在Startup类之外的地方注入我的服务呢,都写在startup里看着好乱:我该如何在程序的其他地方获取我注入的服务呢:下面给大家写篇文章帮助大家学习. 一.如何在Stratup类外注入服务 首先,我们看startup类的ConfigureServices方法,我们会发现我们所有的服务都是使用IServiceCollection注入进去的 所以我们在其他地方进行注入依然是使用这个接口进行注入,话不多说,上源码 我们首先定义一个静态类,然后在静态类内写一个IServiceCo

  • 详解asp.net core 依赖注入

    前言 好久没有写微博了,因为前段时间由于家庭原因决定从工作了3年多的北京转移到上海去.依赖注入在学习net core的时候也有写过类似的东西,只是实践的较少,结果来到上海新公司系统框架涉及到了这块知识点,所以在了解完自己的项目之后决定做一些相关的总结.接下来就让我们先来了解hewi依赖注入. 什么是依赖注入 依赖注入,全称是"依赖注入到容器", 容器(IOC容器)是一个设计模式,它也是个对象,你把某个类(不管有多少依赖关系)放入这个容器中,可以"解析"出这个类的实例

  • ASP.NET Core DI手动获取注入对象的方法

    依赖注入简单介绍: 依赖注入(Dependency injection , DI)是一种实现对象及其合作者或依赖项之间松散耦合的技术.将类用来执行其操作的这些对象以某种方式提供给该类,而不是直接实例化合作者或使用静态引用. ASP.NET Core DI 一般使用构造函数注入获取对象,比如在ConfigureServices配置注入后,通过下面方式获取: private IValueService _valueService; public ValueController(IValueServi

  • .NET Core源码解析配置文件及依赖注入

    写在前面 上篇文章我给大家讲解了ASP.NET Core的概念及为什么使用它,接着带着你一步一步的配置了.NET Core的开发环境并创建了一个ASP.NET Core的mvc项目,同时又通过一个实战教你如何在页面显示一个Content的列表.不知道你有没有跟着敲下代码,千万不要做眼高手低的人哦. 这篇文章我们就会设计一些复杂的概念了,因为要对ASP.NET Core的启动及运行原理.配置文件的加载过程进行分析,依赖注入,控制反转等概念的讲解等. 俗话说,授人以鱼不如授人以渔,所以文章旨在带着大

  • ASP.NET Core 过滤器中使用依赖注入知识点总结

    如何给过滤器ActionFilterAttribute也用上构造函数注入呢? 一般自定义的过滤器直接用特性方式标识就能使用 [ContentFilter] 因为构造函数在使用的时候要求传参,然后我们可以使用这个 ServiceFilter 在ASP.NET Core里,我们可以使用ServiceFilter来完成这个需求. ServiceFilter允许我们解析一个已经添加IoC容器的服务,因此我们需要把ContentFilter注册一下. services.AddScoped<ContentF

  • 在.NET Core控制台程序中如何使用依赖注入详解

    背景介绍 Dependency Injection:又称依赖注入,简称DI.在以前的开发方式中,层与层之间.类与类之间都是通过new一个对方的实例进行相互调用,这样在开发过程中有一个好处,可以清晰的知道在使用哪个具体的实现.随着软件体积越来越庞大,逻辑越来越复杂,当需要更换实现方式,或者依赖第三方系统的某些接口时,这种相互之间持有具体实现的方式不再合适.为了应对这种情况,就要采用契约式编程:相互之间依赖于规定好的契约(接口),不依赖于具体的实现.这样带来的好处是相互之间的依赖变得非常简单,又称松

  • ASP.NET Core依赖注入系列教程之服务的注册与提供

    前言 在采用了依赖注入的应用中,我们总是直接利用DI容器直接获取所需的服务实例,换句话说,DI容器起到了一个服务提供者的角色,它能够根据我们提供的服务描述信息提供一个可用的服务对象.ASP.NET Core中的DI容器体现为一个实现了IServiceProvider接口的对象. ServiceProvider与ServiceDescriptor 服务的注册与提供     利用ServiceProvider来提供服务     提供一个服务实例的集合     获取ServiceProvider自身对

  • 在.net core中实现字段和属性注入的示例代码

    简单来说,使用Ioc模式需要两个步骤,第一是把服务注册到容器中,第二是从容器中获取服务,我们一个一个讨论并演化.这里不会考虑使用如Autofac等第三方的容器来代替默认容器,只是提供一些简单实用的小方法用于简化应用层的开发. 将服务注入到容器 asp.netcore官方给出的在容器中注册服务方法是,要在Startup类的ConfigureServices方法中添加服务,如下所示: public void ConfigureServices(IServiceCollection services)

  • .NET Core中创建和使用NuGet包的示例代码

    在.NET Core的项目中,如果我们要在项目中引用其它DLL文件,不建议直接在项目引用中添加DLL文件(虽然在.NET Core项目中也可以这么做),建议是去直接下载DLL文件所属的NuGet包.这样最大的好处是我们可以将要引用DLL文件的所有依赖文件也一起引入到项目中,这样保证了引用文件的完整性,让其可以正确地运行. 下面我们通过一个.NET Core类库项目和一个ASP.NET Core项目,来演示怎么发布一个NuGet包,并在项目中引用该NuGet包. 首先我们新建一个.NET Core

  • SpringBoot中整合Shiro实现权限管理的示例代码

    之前在 SSM 项目中使用过 shiro,发现 shiro 的权限管理做的真不错,但是在 SSM 项目中的配置太繁杂了,于是这次在 SpringBoot 中使用了 shiro,下面一起看看吧 一.简介 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理.使用Shiro的易于理解的API,您可以快速.轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序. 三个核心组件: 1.Subject 即"当前操作用户".但是,在 Shi

  • Python中xml和dict格式转换的示例代码

    在做接口自动化的时候,请求数据之前都是JSON格式的,Python有自带的包来解决.最近在做APP的接口,遇到XML格式的请求数据,费了很大劲来解决,解决方式是:接口文档拿到的是XML,在线转化为json格式(目的是拿到xml数据的模板),存放到json文件中,根据接口名去提取. github原文介绍:使用XML的Python模块感觉就像您在使用JSON 链接:https://github.com/martinblech/xmltodict 下载xmltodict(pip install xml

  • vue中el-upload上传图片到七牛的示例代码

    一.思路,从后台获取七牛token,上传图片到七牛,获取返回图片路径放入el-upload. 二.代码. <el-input v-model="listVideoQuery.orgLogo" @change="orgLogoChange"></el-input> <el-col :span="10" class="mt10"> <el-upload class="upload

  • jstree中的checkbox默认选中和隐藏示例代码

    jstree复选框自定义显示隐藏和初始化默认选中 首先需要配置 Checkbox plugin "plugins" : ['checkbox'] 设置默认选中状态(checkbox 选中) state: {checked: true} $.jstree.defaults.checkbox.tie_selection 示例: $('#demo_tree').jstree({ "core" : { 'data': [ { "id" : "a

  • IDEA 中创建Spring Data Jpa 项目的示例代码

    一.IDEA 创建工程 使用IDEA 创建工程的过程,使用文字做简单描述. 选择工程类别[Spring Initializr]. 设置工程的元数据[Metadata],根据自己的情况填写即可. 设置工程的依赖:在[Web]中选择"Spring Web";在[SQL]中选中"Spring Data JPA"."Spring Data JDBC"."MySQL Driver"."JDBC API".选中的可能有

  • 详解Python中@staticmethod和@classmethod区别及使用示例代码

    本文主要介绍Python中,class(类)的装饰器@staticmethod和@classmethod的使用示例代码和它们的区别. 1.@staticmethod和@classmethod区别 @staticmethod:静态方法 @classmethod:类方法 一般来说,要使用某个类的方法,需要先实例化一个对象再调用方法. 而使用@staticmethod或@classmethod,就可以不需要实例化,直接通过类名就可以实现调用 使用:直接类名.方法名()来调用.@staticmethod

  • nodejs中使用HTTP分块响应和定时器示例代码

    在本例中,将要创建一个输出纯文本的HTTP服务器,输出的纯文本每隔一秒会新增100个用换行符分隔的时间戳. require('http').createServer(function(req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); var left = 10; var interval = setInterval(function() { for(var i = 0; i< 100; i++) { res.write

  • python 中if else 语句的作用及示例代码

    引入:if-else的作用,满足一个条件做什么,否则做什么. if-else语句语法结构 if 判断条件: 要执行的代码 else: 要执行的代码 判断条件:一般为关系表达式或bool类型的值 执行过程:程序运行到if处,首先判断所带的条件,如果条件成立,就是返回值是True,则执行下面的代码:如果条件不成立则返回值是False, 则继续执行下面的代码. 示例1:模拟用户登录 提示输入用户名和密码 如果用户名是Admin,密码等于123.com, 提示用户登录成功 如果用户名不是Admin,提示

随机推荐