spring boot基于Java的容器配置讲解

spring容器是负责实例化、配置、组装组件的容器。

容器的配置有很多,常用的是xml、Java注解和Java代码。

在spring中Ioc容器相关部分是context和beans中。其中context-support保存着许多线程的容器实现。比如AnnotationConfigApplicationContext或者ClassPathXmlApplicationContext。两者只有接收的目标不同,前者接收Java类后者接收Xml文件。但作为spring容器的不同实现殊途同归。

下面我通过spring文档中的介绍来自己过一遍容器配置,来加深印象。这里我使用的是springboot。所以有些基于web.xml的配置不会涉及到。

@Bean和@Configuration

@Configuration注解的类,表示这个类是一个配置类,类似于<beans></beans>或者.xml文件。

@Bean注解用来说明使用springIoc容器管理一个新对象的实例化、配置和初始化。类似于<bean></bean>,默认情况下,bean名称就是方法名称.

例子:

@Configuration
public class Conf {

  @Bean
  public HelloService helloService() {
    return new HelloServiceImpl();
  }

}

这种配置方式就类似于xml配置中的

<beans>
  <bean id="helloService" class="com.dust.service.impl.HelloServiceImpl" />
</beans>

等价于注解配置中的

@Service
public class HelloServiceIMpl implements HelloService {

  @Override
  public String hello() {
    return "hello world";
  }

}

使用AnnotationConfigApplicationContext实例化Spring容器

这是在spring3.0加入的功能,除了接收@Configuration注解的类作为输入类之外还可以接受使用JSR-330元数据注解的简单类和@Component类。

当@Configuration注解的类作为输入时,@Configuration类本身会被注册为一个bean,在这个类中所有用@Bean注解的方法都会被定义为一个bean。

具体有哪些类型的bean可以方法遍历打印容器中的bean。

  public static void main(String[] args) {
    ApplicationContext context = new AnnotationConfigApplicationContext(Conf.class);
    HelloService helloService = context.getBean(HelloService.class);
    String hello = helloService.hello();
    System.out.println(hello);
  }

该实例的步骤为:

1. 创建AnnotationConfigApplicationContext容器对象,同时将@Configuration注解的Conf.class作为参数传入。
2. 容器回根据传入的Conf类来构建bean。其中就有helloService
3. 通过bean的对象类型获取到容器中保管的对象。
4. 执行对象方法

但是AnnotationConfigApplicationContext并不仅使用@Configuration类。任何@Component或JSR-330注解的类都可以作为输入提供给构造函数。例如:

  public static void main(String[] args) {
    ApplicationContext context = new AnnotationConfigApplicationContext(HelloServiceImpl.class, A.class, B.class);
    HelloService helloService = context.getBean(HelloService.class);
    String hello = helloService.hello();
    System.out.println(hello);
  }

上面假设MyServiceImpl、A和B都用了Spring的依赖注入的注解,例如@Autowired。

使用register(Class<?>…)的方式构建容器

也可以使用无参构造函数实例化AnnotationConfigApplicationContext,然后使用register()方法配置。当使用编程方式构建AnnotationConfigApplicationContext时,这种方法特别有用。

例子:

  public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(Conf.class);
    context.refresh();
    HelloService helloService = context.getBean(HelloService.class);
    String hello = helloService.hello();
    System.out.println(hello);
  }

其中的refresh方法是一个初始化工作。否则注册的类并不会被生成bean。

使用scan(String …)组件扫描

组件扫描,只需要设置好对应包路径,spring容器回自动扫描包下面所有能够被容器初始化的Java类。

使用注解:

@Configuration
@ComponentScan("com.example.springdemo.beans")
public class Conf {

  @Bean
  public HelloService helloService() {
    //用这种方法创建的service相当于用@Service注解标注
    return new HelloServiceImpl();
  }

}

在该路径下还有一个配置文件:

@Configuration
public class Conf2 {

  @Bean
  public ByeService byeService() {
    //用这种方法创建的service相当于用@Service注解标注
    return new ByeServiceImpl();
  }

}

然后是初始化容器:

  public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(Conf.class);
    context.refresh();
    ByeService byeService = context.getBean(ByeService.class);
    String hello = byeService.bye();
    System.out.println(hello);
  }

可以看到,虽然传入的是Conf类,但是由于包扫描机制,该容器同时创建了Conf2类中的bean。

这就类似xml配置中的:

<beans>
  <context:component-scan base-package="com.example.springdemo.beans"/>
</beans>

还可以直接调用容器的扫描方法

  public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//    context.register(Conf.class);
    context.scan("com.example.springdemo.beans");
    context.refresh();
    ByeService byeService = context.getBean(ByeService.class);
    String hello = byeService.bye();
    System.out.println(hello);
  }

springboot中的包扫描

springboot通过main方法启动,其中的注解为@SpringBootApplication。通过查看该注解的代码可以发现一下代码段:

@AliasFor(
  annotation = ComponentScan.class,
  attribute = "basePackages"
)

由此可以知道@SpringBootApplication注解包括了包扫描注解,同时扫描的是该类的目录以及子目录的所有可以被spring容器初始化的类

AnnotationConfigWebApplicationContext对于web应用的支持

AnnotationConfigApplicationContext在WebApplicationContext中的变体为 AnnotationConfigWebApplicationContext。当配置Spring ContextLoaderListener servlet 监听器、Spring MVC DispatcherServlet的时候,可以用此实现。

Bean依赖

@Bean注解方法可以具有描述构建该bean所需依赖关系的任意数量的参数。依赖的必须也是Ioc容器中注册的bean。

将上面的代码修改后如下:

@Configuration
public class Conf {

  @Bean
  public HelloService helloService(ByeService byeService) {
    return new HelloServiceImpl(byeService);
  }

  @Bean
  public ByeService byeService() {
    return new ByeServiceImpl();
  }

}
public class HelloServiceImpl implements HelloService {

  private ByeService byeService;

  public HelloServiceImpl(ByeService byeService) {
    this.byeService = byeService;
  }

  @Override
  public String hello() {
    return "hello world" + byeService.bye();
  }

}
  public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(Conf.class);
    context.refresh();
    HelloService helloService = context.getBean(HelloService.class);
    String hello = helloService.hello();
    System.out.println(hello);
    ByeService byeService = context.getBean(ByeService.class);
    String bye = byeService.bye();
    System.out.println(bye);
  }

输出结果:

hello worldGoodbye!

Goodbye!

这种解决原理和基于构造函数的依赖注入几乎相同。

生命周期回调

@Bean注解支持任意的初始化和销毁回调方法,这与Spring XML 中bean元素上的init方法和destroy-method属性非常相似:

  @Bean(initMethod = "init")
  public HelloService helloService(ByeService byeService) {
    return new HelloServiceImpl(byeService);
  }

  @Bean(destroyMethod = "destroy")
  public ByeService byeService() {
    return new ByeServiceImpl();
  }

public interface ByeService {

  String bye();

  void destroy();

}

public interface HelloService {

  String hello();

  void init();
}

  public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(Conf.class);
    context.refresh();
    context.close();
  }

输出如下:

init helloService!!

destroy byeService!

默认情况下,Ioc容器关闭后所有bean都会被销毁,但是如果要引入一个生命周期在应用程序之外进行管理的组件,例如:DataSource。那么只需要将@Bean(destroyMethod =””)添加到你的bean定义中即可禁用默认(推测)模式。

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

当然,初始化的时候也可以先执行对应方法,而不用交给Ioc容器

  @Bean
  public HelloService helloService(ByeService byeService) {
    HelloService helloService = new HelloServiceImpl(byeService);
    helloService.init();
    return helloService;
  }

@Scope和scope 代理

Scope描述的是Spring容器如何新建Bean实例的。

  1. Singleton:一个Spring容器中只有一个Bean的实例,此为Spring的默认配置,全容器共享一个实例。
  2. Prototype:每次调用新建一个Bean实例。
  3. Request:Web项目中,给每一个 http request 新建一个Bean实例。
  4. Session:Web项目中,给每一个 http session 新建一个Bean实例。
  5. GlobalSession:这个只在portal应用中有用,给每一个 global http session 新建一个Bean实例。
  @Bean
  //每次调用就创建一个新的bean
  @Scope("prototype")
  public UserInfo userInfo() {
    return new UserInfo();
  }

  @Bean
  public UserService userService() {
    UserService userService = new UserServiceImpl();
    userService.init(userInfo());
    return userService;
  }

测试代码:

  public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(Conf.class);
    context.refresh();
    UserService userService = context.getBean(UserService.class);
    UserService userService2 = context.getBean(UserService.class);
    UserInfo userInfo = context.getBean(UserInfo.class);
    UserInfo userInfo2 = context.getBean(UserInfo.class);
    System.out.println(userService == userService2);
    System.out.println(userInfo == userInfo2);
  }

输出:

true

false

自定义Bean命名

通常,bean的名称是bean的方法名,但是可以通过name属性重命名。有时一个单一的bean需要给出多个名称,称为bean别名。为了实现这个目标,@Bean注解的name属性接受一个String数组。

  @Bean(name = {"user", "userService", "User"})
  public UserService userService() {
    UserService userService = new UserServiceImpl();
    userService.init(userInfo());
    return userService;
  }
  public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(Conf.class);
    context.refresh();
    Object user = context.getBean("user");
    Object userService = context.getBean("userService");
    Object User = context.getBean("User");

    System.out.println(user == userService);
    System.out.println(user == User);
    System.out.println(userService == User);
  }

输出:

true

true

true

Bean描述

有时候需要提供一个详细的bean描述文本是非常有用的。当对bean暴露(可能通过JMX)进行监控使,特别有用。可以使用@Description注解对Bean添加描述:

  @Bean(name = {"user", "userService", "User"})
  @Description("这是用户服务对象")
  public UserService userService() {
    UserService userService = new UserServiceImpl();
    userService.init(userInfo());
    return userService;
  }
  public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(Conf.class);
    context.refresh();
    String description = context.getBeanDefinition("user").getDescription();
    System.out.println(description);
  }

输出:

这是用户服务对象

基于Java组合配置

使用@Import注解

和Spring XML文件中使用元素来帮助模块化配置类似,@Import注解允许从另一个配置类加载@Bean定义:

@Configuration
@Import(UserConf.class)
public class Conf {

  @Bean(initMethod = "init")
  public HelloService helloService(ByeService byeService) {
    //用这种方法创建的service相当于用@Service注解标注
    return new HelloServiceImpl(byeService);
  }

  @Bean(destroyMethod = "destroy")
  public ByeService byeService() {
    return new ByeServiceImpl();
  }

}
@Configuration
public class UserConf {

  @Bean
  //每次调用就创建一个新的bean
  @Scope("prototype")
  public UserInfo userInfo() {
    return new UserInfo();
  }

  @Bean(name = {"user", "userService", "User"})
  @Description("这是用户服务对象")
  public UserService userService() {
    UserService userService = new UserServiceImpl();
    userService.init(userInfo());
    return userService;
  }

}
  public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(Conf.class);
    context.refresh();
    String description = context.getBeanDefinition("user").getDescription();
    System.out.println(description);
  }

这种方法简化了容器实例化,因为只需要处理一个类,而不是需要开发人员在构建期间记住大量的@Configuration注解类。

Java and XML 混合配置

Java配置并不能100%替代xml配置,因此Ioc容器支持两者混合配置。不过这里有个区别就是以xml为中心还是以Java配置为中心。

以XML为中心

@Configuration
public class DataSourceConf {

  @Autowired
  private DataSource dataSource;

  @Bean
  public DataSourceService dataSource() {
    return new DataSourceerviceImpl(dataSource);
  }

}
jdbc.url=jdbc:mysql://39.108.119.174:3306/dust
jdbc.username=root
jdbc.password=123456
<beans>

  <context:annotation-config/>

  <context:property-placeholder location="classpath:jdbc.properties"/>

  <bean class="com.example.springdemo.beans.DataSourceConf"/>

  <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
  </bean>

</beans>
  public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/datasource.xml");
    DataSourceService dataSourceService = context.getBean(DataSourceService.class);
    System.out.println(dataSourceService.toString());
  }

以Java类为中心

<beans>
  <context:property-placeholder location="classpath:jdbc.properties"/>
</beans>
@Configuration
@ImportResource("classpath:spring/datasource.xml")
public class DataSourceConf {

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

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

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

  @Bean
  public DataSourceService dataSource() {
    return new DataSourceerviceImpl(url, username, password);
  }

}
  public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.scan("com.example.springdemo.beans");
    context.refresh();
    DataSourceService dataSourceService = context.getBean(DataSourceService.class);
    System.out.println(dataSourceService.toString());

//    ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/datasource.xml");
//    DataSourceService dataSourceService = context.getBean(DataSourceService.class);
//    System.out.println(dataSourceService.toString());
  }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • springboot的java配置方式(实例讲解)

    1.创建User实体类. @Data public class User { private String username; private String password; private Integer age; } 2.创建UserDao用于模拟数据库交互. public class UserDao{ public List<User> queryUserList() { List<User> result = new ArrayList<User>(); //

  • SpringBoot之Java配置的实现

    Java配置也是Spring4.0推荐的配置方式,完全可以取代XML的配置方式,也是SpringBoot推荐的方式. Java配置是通过@Configuation和@Bean来实现的: 1.@Configuation注解,说明此类是配置类,相当于Spring的XML方式 2.@Bean注解,注解在方法上,当前方法返回的是一个Bean eg: 此类没有使用@Service等注解方式 package com.wisely.heighlight_spring4.ch1.javaconfig; publ

  • spring boot基于Java的容器配置讲解

    spring容器是负责实例化.配置.组装组件的容器. 容器的配置有很多,常用的是xml.Java注解和Java代码. 在spring中Ioc容器相关部分是context和beans中.其中context-support保存着许多线程的容器实现.比如AnnotationConfigApplicationContext或者ClassPathXmlApplicationContext.两者只有接收的目标不同,前者接收Java类后者接收Xml文件.但作为spring容器的不同实现殊途同归. 下面我通过s

  • 在Spring中基于Java类进行配置的完整步骤

    前言 JavaConfig 原来是 Spring 的一个子项目,它通过 Java 类的方式提供 Bean 的定义信息,在 Spring4 的版本, JavaConfig 已正式成为 Spring4 的核心功能 . 本文将详细介绍关于Spring中基于Java类进行配置的相关内容,下面话不多说了,来一起看看详细的介绍吧 1 定义 Bean 普通的 POJO 只要标注了 @Configuration 注解,就可以为 Spring 容器提供 Bean 的定义信息. @Configuration pub

  • spring boot实战之内嵌容器tomcat配置

    本文介绍了spring boot实战之内嵌容器tomcat配置,分享给大家,具体如下: 默认容器 spring boot默认web程序启用tomcat内嵌容器tomcat,监听8080端口,servletPath默认为 / 通过需要用到的就是端口.上下文路径的修改,在spring boot中其修改方法及其简单: 在资源文件中配置: server.port=9090 server.contextPath=/lkl 启动spring boot 2015-10-04 00:06:55.768 INFO

  • Spring boot基于JPA访问MySQL数据库的实现

    本文展示如何通过JPA访问MySQL数据库. JPA全称Java Persistence API,即Java持久化API,它为Java开发人员提供了一种对象/关系映射工具来管理Java应用中的关系数据,结合其他ORM的使用,能达到简化开发流程的目的,使开发者能够专注于实现自己的业务逻辑上. Spring boot结合Jpa 能够简化创建 JPA 数据访问层和跨存储的持久层功能,用户的持久层Dao接口只需要继承定义好的接口,无需再写实现类,就可以实现对象的CRUD操作以及分页排序等功能. 环境要求

  • Spring Boot应用开发初探与实例讲解

    Spring Boot是由Pivotal团队提供的全新Spring开发框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程. 从它的名字可以看出,Spring Boot 的作用在于创建和启动新的基于 Spring 框架的项目. 它的目的是帮助开发人员很容易的创建出独立运行和产品级别的基于 Spring 框架的应用. 它包含的特性如下: 应用独立运行,对于Web应用直接嵌入应用服务器(Tomcat or Jetty) 根据项目的依赖(Maven or Gradle中定义的依赖)自动配

  • Spring Boot 详细分析Conditional自动化配置注解

    目录 1. Spring Boot Condition功能与作用 2. Conditional条件化系列注解介绍 3. Conditional条件化注解的实现原理 4. Conditional核心之matches匹配接口 5. Conditional核心之条件化注解具体实现 6. 总结 1. Spring Boot Condition功能与作用 @Conditional是基于条件的自动化配置注解, 由Spring 4框架推出的新特性. 在一个服务工程, 通常会存在多个配置环境, 比如常见的DEV

  • 详解Spring Boot 使用Java代码创建Bean并注册到Spring中

    从 Spring3.0 开始,增加了一种新的途经来配置Bean Definition,这就是通过 Java Code 配置 Bean Definition. 与Xml和Annotation两种配置方式不同点在于: 前两种Xml和Annotation的配置方式为预定义方式,即开发人员通过 XML 文件或者 Annotation 预定义配置 bean 的各种属性后,启动 spring 容器,Spring 容器会首先解析这些配置属性,生成对应都?Bean Definition,装入到 DefaultL

  • Spring Boot实战教程之自动配置详解

    前言 大家应该都有所了解,随着Ruby.Groovy等动态语言的流行,相比较之下Java的开发显得格外笨重.繁多的配置.低下的开发效率.复杂的部署流程以及第三方技术集成难度大等问题一直被人们所诟病.随着Spring家族中的新星Spring Boot的诞生,这些问题都在逐渐被解决. 个人觉得Spring Boot中最重要的两个优势就是可以使用starter简化依赖配置和Spring的自动配置.下面这篇文章将给大家详细介绍Spring Boot自动配置的相关内容,话不多说,来一起看看详细的介绍. 使

  • spring boot+mybatis 多数据源切换(实例讲解)

    由于公司业务划分了多个数据库,开发一个项目会同事调用多个库,经过学习我们采用了注解+aop的方式实现的 1.首先定义一个注解类 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface TargetDataSource { String value();//此处接收的是数据源的名称 } 2.然后建一个配置类,这个在项目启动时会加载数据源,一开始采用了HikariCP,查资料说是最快性能最好的

  • Spring Boot使用Druid和监控配置方法

    Spring Boot默认的数据源是:org.apache.tomcat.jdbc.pool.DataSource Druid是Java语言中最好的数据库连接池,并且能够提供强大的监控和扩展功能. 下面来说明如何在 Spring Boot 中配置使用Druid (1)添加Maven依赖 (或jar包)\ <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId&g

随机推荐