Bootstrap

Spring 5 中文解析核心篇-IoC容器之基于Java容器配置

1.12 基于Java容器配置

这个部分涵盖了在你的Java代码中怎样去使用注解配置Spring容器。它包含下面的主题:

1.12.1 基本概念:@Bean和

Spring的新Java配置支持中的主要构件是注解的类和注解的方法。

注解使用表示一个方法实例、配置和实例化Spring IoC容器管理的新对象。这些类似Spring的 XML配置,注解扮演了元素相同的角色。你可以使用注解方法替换任何Spring中组件。然而,它们最常与@Configuration一起使用。注解类注解表示它的主要目的是bean定义的源。此外,类允许通过调用同一类中的其他方法来定义Bean间的依赖关系。下面最简单的例子:

@Configuration
public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyServiceImpl();
    }
}

前面的AppConfig类是与下面的Spring XML定义相等:


    

​  完整的与“精简” 模式?

当方法在类中被声明时,这些类没有被注解,它们被称为以“精简”模式进行处理。在或在简单的旧类中声明的Bean方法被认为是“精简版”,其中包含类的主要目的不同,而方法在那里具有某种优势。例如,服务组件在每个可应用的组件类上通过增加一个附加的@Bean方法暴露管理视图到容器。在这种场景下,方法是一种通用的工厂方法机制。

不像完整的,精简方法不能声明bean之间的依赖关系。相反,它们对其包含的组件的内部状态以及可能声明的参数(可选)进行操作。因此,此类方法不应调用其他方法。每个这样的方法实际上只是一个特定bean引用的工厂方法,没有任何特殊的运行时语义。这里的积极副作用是在运行时不需要应用CGLIB子类,所以在类设计方面没有限制(也就是,包含类可能是final)。

在常见的场景中,方法是在@Configuration类中声明的,确保总是使用完整模式,因此交叉方法引用被重定向到容器的生命周期管理。这可以防止通过常规Java调用意外调用相同的方法,这有助于减少在lite模式下操作时难以跟踪的细微错误。备注:在类中调用其他方法会定向到容器的生命周期管理。

和在下面的部分深入讨论。首先,我们会覆盖基于Java注解创建Spring容器的各种方式。

1.12.2 通过使用初始化Spring容器

以下各节介绍了Spring 3.0中引入的Spring的。这个通用的ApplicationContext实现不仅能够接收类作为输入,还能够接收普通的类和使用JSR-330元数据注解的类

当类作为输入被提供,类自身作为一个bean定义被注册并且所有在类中被声明的方法也作为bean的定义被注册到容器。

当提供和JSR-330类时,它们被注册为bean定义,并假设DI元数据(如或)在这些类中使用。

简单构造

与实例化时将Spring XML文件用作输入的方式几乎相同,实例化时可以将类用作输入。如下面的示例所示,这允许完全不使用XML来使用Spring容器:

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    MyService myService = ctx.getBean(MyService.class);
    myService.doStuff();
}

像前面提到的,不限于与@Configuration一起使用。任何或JSR-330注解的类作为输入构造是被支持,类似下面例子:

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.class);
    MyService myService = ctx.getBean(MyService.class);
    myService.doStuff();
}

前面的例子假设、、和使用Spring依赖注入注解例如:。

通过使用编程式的构建容器

你可以通过使用无参构造函数实例化并且通过使用方法配置。当编程地构建时,这个方法是特别地有用。下面类中展示怎样去使用:

public static void main(String[] args) {
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
    ctx.register(AppConfig.class, OtherConfig.class);
    ctx.register(AdditionalConfig.class);
    ctx.refresh();
    MyService myService = ctx.getBean(MyService.class);
    myService.doStuff();
}

通过扫描激活组件

扫描激活组件,你可以注解你的类:

@Configuration
@ComponentScan(basePackages = "com.acme") //1
public class AppConfig  {
    ...
}

经验丰富的Spring用户可能熟悉Spring context 中等效的XML声明:命名空间,类似下面例子:


 

在前面的例子中,包被扫描去查找被注解的类,并且这些类作为Spring bean定义被注册在容器中。暴露方法提供相同的组件扫描功能,类似下面的例子:

public static void main(String[] args) {
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
    ctx.scan("com.acme");
    ctx.refresh();
    MyService myService = ctx.getBean(MyService.class);
}

记住类是使用元注解的,因此它们是组件扫描的候选者。在前面的例子中,假设AppConfig被声明在包中(或任何子包),它会在调用期间被选出来。在后,其所有方法都将被处理并注册为容器内的Bean定义。

通过支持Web应用程序

提供了的变体。当配置Spring的 servlet监听器、Spring MVC  等等的时候,你可以使用这个实现,下面的片段配置一个典型的Spring MVC web应用程序(注意:使用和):


    
    
        contextClass
        
            org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        
    

    
    
        contextConfigLocation
        com.acme.AppConfig
    

    
    
        org.springframework.web.context.ContextLoaderListener
    

    
    
        dispatcher
        org.springframework.web.servlet.DispatcherServlet
        
        
            contextClass
            
                org.springframework.web.context.support.AnnotationConfigWebApplicationContext
            
        
        
        
            contextConfigLocation
            com.acme.web.MvcConfig
        
    

    
    
        dispatcher
        /app/*
    

1.12.3 使用@Bean注解

是一个方法级别注解并且是XML 元素的直接类比物。这个注解支持一些通过提供的属性,例如:  、 、 

你可以在和注解的类上使用注解。

声明Bean

去声明一个bean,你可以为一个方法注解。你使用这个方法在中去注册一个方法返回值指定类型的bean定义。默认情况,bean名称是相同方法名称。下面的例子显示一个方法声明:

@Configuration
public class AppConfig {

    @Bean
    public TransferServiceImpl transferService() {
        return new TransferServiceImpl();
    }
}

前面的配置与下面的Spring XML完全等效:


    

这两者声明都使一个名为的bean在中可用,并绑定一个类型的对象实例,类似下面文本图片显示:

transferService -> com.acme.TransferServiceImpl

你也可以声明你的方法为一个接口(或者基类)返回类型,类似下面例子展示:

@Configuration
public class AppConfig {

    @Bean
    public TransferService transferService() {
        return new TransferServiceImpl();
    }
}

但是,这将高级类型预测的可见性限制为指定的接口类型()。然而,全类型()在容器只有一个,受影响的单例bean被初始化。非懒加载单例bean根据它们的声明顺序获取已经初始化实例,当其他组件尝试通过非声明类型去匹配时,你可能看到不同类型匹配结果依赖(例如,  ,仅在实例化 bean之后才解析)。

如果你始终通过声明的服务接口引用你的类型,那么你的返回类型可以安全地加入该设计决策。但是,对于实现多个接口的组件或由其实现类型潜在引用的组件,声明最具体的返回类型(至少与引用你的bean的注入点所要求的具体类型一样)更为安全。 备注:意思是如果通过实现类型引用组件时,在定义方法时返回类型要是具体的实现类型。

Bean依赖

一个被注解的方法可以有任意个参数,这些参数描述了需要的依赖去构建bean。例如,如果我们的需要一个,我们可以通过方法参数来实现这种依赖关系,类似下面例子:

@Configuration
public class AppConfig {

    @Bean
    public TransferService transferService(AccountRepository accountRepository) {
        return new TransferServiceImpl(accountRepository);
    }
}

解析机制与基于构造函数的依赖注入几乎相同。查看更详细

接受生命周期回调

任何被声明注解的类支持普通的生命周期回调并且可以使用 JSR-250的和@PreDestroy注解。查看更多的详情。

常规的Spring生命周期回调是被完全的支持。如果bean实现、或,它们各自的方法被容器回调。

标准的set 接口(例如,,、,、等等)也是完全的被支持。

注解支持任意的初始化和销毁回调方法,非常类似Spring 中XML元素的init-method和属性,类似下面例子显示:

public class BeanOne {

    public void init() {
        // initialization logic
    }
}

public class BeanTwo {

    public void cleanup() {
        // destruction logic
    }
}

@Configuration
public class AppConfig {

    @Bean(initMethod = "init")
    public BeanOne beanOne() {
        return new BeanOne();
    }

    @Bean(destroyMethod = "cleanup")
    public BeanTwo beanTwo() {
        return new BeanTwo();
    }
}

默认情况下,这些bean通过Java配置定义它们有公共的或方法自定地加入到销毁回调中。如果你有一个公共的或方法并且当容器被关闭时不想被回调,你应该增加到你的bean定义中去禁止默认的()模式。

默认情况下,你可能要对通过JNDI获取的资源执行此操作,因为其生命周期在应用程序外部进行管理的。特别是,要确保始终为数据源执行此操作,因为在Java EE应用服务器上这是有问题的。

下面的例子展示怎样去阻止DataSource自动销毁回调。

@Bean(destroyMethod="")
public DataSource dataSource() throws NamingException {
    return (DataSource) jndiTemplate.lookup("MyDS");
}

另外,对于方法,通常使用编程式地JNDI查找,方法是使用Spring的或帮助器,或者直接使用JNDI 用法,而不使用变体(这将迫使你将返回类型声明为类型,而不是实际的类型。目标类型,因此很难在打算引用此处提供的资源的其他@Bean方法中用于交叉引用调用。

对于前面示例中的BeanOne,它等效于在构造期间直接调用方法,类似下面例子:

@Configuration
public class AppConfig {

    @Bean
    public BeanOne beanOne() {
        BeanOne beanOne = new BeanOne();
        beanOne.init();
        return beanOne;
    }

    // ...
}

当你直接地工作在Java中,你可以对你的对象做任何事而不需要依赖容器生命周期。

指定Bean作用域

Spring包括注解,因此你可以使用bean的作用域。

使用注解

你可以指定你的bean定义通过注解同时也可以指定一个作用域。你可以使用中任何标准的作用域指定。

默认作用域是,但是你可以覆盖这个通过注解,类似下面例子显示:

@Configuration
public class MyConfiguration {

    @Bean
    @Scope("prototype")
    public Encryptor encryptor() {
        // ...
    }
}

Spring提供通过处理作用域依赖的便捷方式。当使用XML配置是最简单创建一个代理方式。使用注解在Java中配置bean,可以通过属性提供同等的支持。默认是没有代理(),但是你可以指定或

如果你使用Java,将XML参考文档中的作用域代理示例(请参阅作用域代理)移植到我们的,它类似于以下内容:

// Http session作用域bean 暴露为代理
@Bean
@SessionScope
public UserPreferences userPreferences() {
    return new UserPreferences();
}

@Bean
public Service userService() {
    UserService service = new SimpleUserService();
    // 引用UserPreferences
    service.setUserPreferences(userPreferences());
    return service;
}

自定义Bean名称

默认情况下,配置类使用方法的名称作为bean名称。这个功能可以被覆盖,通过的name属性,类似下面例子:

@Configuration
public class AppConfig {

   @Bean(name = "myThing")
   public Thing thing() {
       return new Thing();
   }
}

Bean别名

类似在中讨论,有时候给一个简单bean多个名称,也称为Bean别名。注解的name属性接受一个字符串数组为这个别名。下面例子展示怎样去设置bean的别名:

@Configuration
public class AppConfig {

    @Bean({"dataSource", "subsystemA-dataSource", "subsystemB-dataSource"})
    public DataSource dataSource() {
        // instantiate, configure and return DataSource bean...
    }
}

@Bean描述

有时候,有助于提供有关bean的更详细的文本描述。当这些bean被暴露为监控目的时,是非常有用的。

去增加一个描述到,你可以使用  注解,类似下面例子展示:

@Configuration
public class AppConfig {

    @Bean
    @Description("Provides a basic example of a bean")
    public Thing thing() {
        return new Thing();
    }
}

1.12.4 使用注解

是一个类级别注解,它表示对象是bean定义的源。类声明bean通过公共注解方法。在类上调用方法能被使用去定义Bean之间依赖关系。

bean间注入的依赖关系

当Bean彼此依赖时,表达这种依赖就像让一个bean方法调用另一个一样简单,类似下面例子展示:

@Configuration
public class AppConfig {

    @Bean
    public BeanOne beanOne() {
        return new BeanOne(beanTwo());
    }

    @Bean
    public BeanTwo beanTwo() {
        return new BeanTwo();
    }
}

在前面的例子中,通过构造函数注入引用。

仅仅当方法被声明在类中时,这方法声明bean间的依赖关系有效。你不能通过使用普通的声明bean间的依赖关系。

查找方法注入

如前所述,查找方法注入是一个高级特性,它很少地使用。在一些单例作用域bean依赖原型作用域bean场景,它是非常有用的。使用Java为配置类型实现这个模式提供一种自然方法。下面例子展示怎样去查找方法注入:

public abstract class CommandManager {
    public Object process(Object commandState) {
        // grab a new instance of the appropriate Command interface
        Command command = createCommand();
        // set the state on the (hopefully brand new) Command instance
        command.setState(commandState);
        return command.execute();
    }

    // okay... but where is the implementation of this method?
    protected abstract Command createCommand();
}

通过使用Java配置,在该子类中,你可以创建一个子类,抽象的方法将被覆盖,以使其查找新的(原型)command对象。通过使用Java配置。下面例子展示怎样去做:

@Bean
@Scope("prototype")
public AsyncCommand asyncCommand() {
    AsyncCommand command = new AsyncCommand();
    // inject dependencies here as required
    return command;
}

@Bean
public CommandManager commandManager() {
    // return new anonymous implementation of CommandManager with createCommand()
    // overridden to return a new prototype Command object
    return new CommandManager() {
        protected Command createCommand() {
            return asyncCommand();
        }
    }
}

有关基于Java的配置在内部如何工作的更多信息

考虑下面例子,它展示了一个注解的方法被调用两次。

@Configuration
public class AppConfig {

    @Bean
    public ClientService clientService1() {
        ClientServiceImpl clientService = new ClientServiceImpl();
        clientService.setClientDao(clientDao());
        return clientService;
    }

    @Bean
    public ClientService clientService2() {
        ClientServiceImpl clientService = new ClientServiceImpl();
        clientService.setClientDao(clientDao());
        return clientService;
    }

    @Bean
    public ClientDao clientDao() {
        return new ClientDaoImpl();
    }
}

)在被调用一次并且在也调用一次。因为这个方法创建一个新的实例并且返回它,你通常希望有两个实例(每个服务一个)。那肯定是有问题的:在Spring中,默认情况实例化bean作用域是。这就是神奇之处:所有类在运行时是CGLIB的子类。在子类中,在调用父方法创建实例之前,子类方法首先检查容器缓存bean。

这种行为根据你的bean作用域可能不同。我们在这里讨论的单例bean。

在Spring3.2以后,不在需要添加CGLIB到你的类路径下,因为CGLIB类已经被重新打包在下并且直接地包含在 jar中。

由于CGLIB在启动时会动态添加功能,因此存在一些限制。特别地,配置类不能是。然而,在Spring4.3以后,任何构造函数在配置类上是被允许的,包括或没有默认参数的构造函数申明默认注入的使用。

如果你想避免CGLIB的限制,考虑在你非类(例如,一个普通的替换)上声明你的方法。在方法之间跨方法调用不会被拦截,因此你必在须构造函数或方法级别只依赖需要注入的。

代码示例:

1.12.5 编写基于Java的配置

Spring的基于Java配置特性允许你编写注解,这样可以降低你的配置复杂性。

使用@Import注解

类似元素被使用在Spring XML文件中去帮助模块化配置,注解允许去其他配置类中加载定义,类似下面的例子展示:

@Configuration
public class ConfigA {

    @Bean
    public A a() {
        return new A();
    }
}

@Configuration
@Import(ConfigA.class)
public class ConfigB {

    @Bean
    public B b() {
        return new B();
    }
}

当初始化上下文时,不需要去指定和,仅仅需要去显示地提供,类似下面例子展示:

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class);

    // now both beans A and B will be available...
    A a = ctx.getBean(A.class);
    B b = ctx.getBean(B.class);
}

这个方式简化容器的实例化,仅仅一个类需要去处理,而不是在构造期间潜在地记住大量的类。

在Spring4.2以后,也支持引用常规的组件类,类似方法。如果你想避免组件扫描,这是非常有用地,通过使用一些配置类作为入口点显示定义所有组件。

在被导入的定义中注入依赖

前面的示例有效,但过于简单。在大多数时间场景中,Bean在配置类之间相互依赖。当使用XML时,这不是问题,因为不涉及编译器并且你可以声明  并信任Spring在容器初始化期间进行处理。当使用类时,Java编译器在配置模型上约束,因为对其他bean引用必须是有效的Java语法。

幸好地,解决这个问题是非常简单的。像,方法可以有任意数量的参数,这些参数描述了bean的依赖。考虑下面更真实的场景对于这些类,每一个bean在其他类中被定义:

@Configuration
public class ServiceConfig {

    @Bean
    public TransferService transferService(AccountRepository accountRepository) {
        return new TransferServiceImpl(accountRepository);
    }
}

@Configuration
public class RepositoryConfig {

    @Bean
    public AccountRepository accountRepository(DataSource dataSource) {
        return new JdbcAccountRepository(dataSource);
    }
}

@Configuration
@Import({ServiceConfig.class, RepositoryConfig.class})
public class SystemTestConfig {

    @Bean
    public DataSource dataSource() {
        // return new DataSource
    }
}

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
    // everything wires up across configuration classes...
    TransferService transferService = ctx.getBean(TransferService.class);
    transferService.transfer(100.00, "A123", "C456");
}

这里有其他的方式去实现相同的结果。记住类最终只是容器中的另一个bean:这意味着它们可以利用和注入以及其他与其他bean相同的特性。

确保以这种方式注入的依赖项只是最简单的一种。类是在上下文初始化期间非常早地处理的,并且强制以这种方式注入依赖项可能导致意外的早期初始化。如上例所示,尽可能使用基于参数的注入。

另外,通过定义和BeanFactoryPostProcessor时要特别小心。这些应该通常地被声明为 方法,不要触发它们包含的配置类初始化。除此之外,和可能在配置类上不能工作,因为它作为bean实例被创建早于 

下面例子展示一个bean怎样被装配到其他bean:

@Configuration
public class ServiceConfig {

    @Autowired
    private AccountRepository accountRepository;

    @Bean
    public TransferService transferService() {
        return new TransferServiceImpl(accountRepository);
    }
}

@Configuration
public class RepositoryConfig {

    private final DataSource dataSource;

    public RepositoryConfig(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Bean
    public AccountRepository accountRepository() {
        return new JdbcAccountRepository(dataSource);
    }
}

@Configuration
@Import({ServiceConfig.class, RepositoryConfig.class})
public class SystemTestConfig {

    @Bean
    public DataSource dataSource() {
        // return new DataSource
    }
}

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
    // everything wires up across configuration classes...
    TransferService transferService = ctx.getBean(TransferService.class);
    transferService.transfer(100.00, "A123", "C456");
}

在类中构造方法注入仅支持在Spring4.3以后。注意:如果目标bean定义仅有一个构造函数,那么不需要去指定。

代码示例:

全限定导入bean以更容易导航

在前面的场景中,使用工作很好并且提供期望的模块化,但是确定自动装配 bean的定义是在哪里声明的仍然有些模棱两可。例如,作为一个开发者看到,怎样确切的知道  bean在哪里定义的?它在代码中不是明确的,这可能很好。记住,  为Eclipse提供可以渲染图形的工具,这些图形显示了所有的对象是怎样连接的,这可能是你需要的。你的Java IDE能更容易地找到所有声明和使用类型并且快速地显示方法的路径以及返回类型。

如果这种歧义是不可接受的,并且你希望从IDE内部直接从一个类导航到另一个类,请考虑自动装配配置类本身。下面例子显示怎样去做:

@Configuration
public class ServiceConfig {

    @Autowired
    private RepositoryConfig repositoryConfig;

    @Bean
    public TransferService transferService() {
        // navigate 'through' the config class to the @Bean method!
        return new TransferServiceImpl(repositoryConfig.accountRepository());
    }
}

在前面情况中,完整的显示定义。但是,现在紧紧的耦合到。这就是需要权衡的。通过使用基于接口或基于抽象类的类,可以在某种程度上缓解这种紧密耦合。考虑下面例子:

@Configuration
public class ServiceConfig {

    @Autowired
    private RepositoryConfig repositoryConfig;

    @Bean
    public TransferService transferService() {
        return new TransferServiceImpl(repositoryConfig.accountRepository());
    }
}

@Configuration
public interface RepositoryConfig {

    @Bean
    AccountRepository accountRepository();
}

@Configuration
public class DefaultRepositoryConfig implements RepositoryConfig {

    @Bean
    public AccountRepository accountRepository() {
        return new JdbcAccountRepository(...);
    }
}

@Configuration
@Import({ServiceConfig.class, DefaultRepositoryConfig.class})  // import the concrete config!
public class SystemTestConfig {

    @Bean
    public DataSource dataSource() {
        // return DataSource
    }

}

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
    TransferService transferService = ctx.getBean(TransferService.class);
    transferService.transfer(100.00, "A123", "C456");
}

现在,与具体的松散耦合,并且内建IDE工具仍然非常有用:你可以容易地获取实现的层级。通过这种方式,导航类及其依赖项与导航基于接口的代码的通常过程没有什么不同。

如果你想流畅启动创建这些bean的顺序,考虑声明它们为(用于首次访问而不是启动时创建)或像其他bean(确保其他指定bean在当前bean被创建之前 ,而不受后者直接依赖关系的影响)。

条件地包含类或方法

根据某些系统状态,有条件地启用或禁用完整的类甚至单个方法,通常很有用。说明:可以启用/禁止类或者类中的方法。一个常用的例子是去使用注解去激活bean,仅仅当在Spring中的指定的被激活时(查看Bean定义 详情)。

注解通过使用一个非常灵活的注解叫做 实现的。注解指示在注册之前应咨询特定实现。

接口的实现接口提供一个方法,它会返回true或false。例如,下面的清单显示对真实实现:

@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    // Read the @Profile annotation attributes
    MultiValueMap attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
    if (attrs != null) {
        for (Object value : attrs.get("value")) {
            if (context.getEnvironment().acceptsProfiles(((String[]) value))) {
                return true;
            }
        }
        return false;
    }
    return true;
}

查看 文档更多详细。

结合Java和XML配置

Spring的类不能的完成替换Spring XML。一些工具(如Spring XML namespaces)仍然是配置容器的理想方法。在使用XML方便或有必要的情况下,你可以选择:使用“以“ XML中心”方式实例化容器,或通过使用和“ Java配置中心”方式实例化容器。 注解可根据需要导入XML。

以XML为中心的类的使用

从XML引导Spring容器并以特别的方式包含类可能更好。例如,在使用Spring XML的大型现有代码库中,根据需要创建类并且现有XML文件中将它们包含在内变得更加容易。在本节的后面,我们将介绍在这种“以XML为中心”的情况下使用类的选项。

  • 声明类似普通的Spring元素

  • 使用 ****选择类

以类为中心的XML与的结合使用

在应用中,类是配置容器的主要机制,但是仍然可能需要至少使用一些XML。在这个场景中,你可以使用和定义你需要的XML。这样做实现了“以Java为中心”的方法来配置容器,并使XML保持在最低限度。下面例子展示了怎样去使用注解去实现“以Java为中心”配置并在需要的时候使用XML:

@Configuration
@ImportResource("classpath:/com/acme/properties-config.xml")
public class AppConfig {

    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    @Bean
    public DataSource dataSource() {
        return new DriverManagerDataSource(url, username, password);
    }
}


    

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    TransferService transferService = ctx.getBean(TransferService.class);
    // ...
}

代码示例:

作者

个人从事金融行业,就职过易极付、思建科技、某网约车平台等重庆一流技术团队,目前就职于某银行负责统一支付系统建设。自身对金融行业有强烈的爱好。同时也实践大数据、数据存储、自动化集成和部署、分布式微服务、响应式编程、人工智能等领域。同时也热衷于技术分享创立公众号和博客站点对知识体系进行分享。

博客地址: 

CSDN: 

微信公众号: