Spring的Java配置方式:@Configuration、@Bean、@ComponentScan注解的使用

1、XML配置方式

在Java项目开发中,使用Spring框架,如果使用传统的XML配置方式,需要首先创建Spring的核心配置文件(applicationContext.xml),然后配置Bean等相关信息。配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
	   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
	   http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

    <!-- Dao层配置 -->
    <bean id="userDao" class="com.pjb.dao.impl.UserDaoImpl">
    </bean>

    <!-- Service层配置 -->
    <bean id="userService" class="com.pjb.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDao"/>
    </bean>

</beans>

调用方式,使用ClassPathXmlApplicationContext类初始化Spring容器对象,然后使用getBean()方法,获取Bean对象。代码如下:

public static void main(String[] args)
{
    //初始化Spring容器(上下文对象)
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    
    //获取Bean对象
    UserService userService = (UserService) applicationContext.getBean("userService");

    //执行业务逻辑方法,获取用户信息
    UserInfo userInfo = userService.getUserInfo();

    //打印结果
    System.out.println("用户编号:" + userInfo.getUserId());
    System.out.println("用户姓名:" + userInfo.getUserName());
    System.out.println("博客地址:" + userInfo.getBlogUrl());
    System.out.println("备注信息:" + userInfo.getRemark());
}

下面将介绍另外一种Spring配置方式:Java配置方式。

2、Java配置方式

Java配置是 Spring 4.x 推荐的配置方式,可以完全替代XML配置;Java配置也是 Spring Boot 推荐的配置方式。

Java配置相关注解:

注解 说明
@Configuration 声明当前类是一个配置类,相当于一个Spring配置的XML文件。
@Bean 该注解在方法上使用,声明当前方法的返回值为一个Bean。
@ComponentScan 自动扫描包名下所有使用@Component、@Repository、@Service、@Controller注解的类,并注册为Bean。
@WishlyConfiguration 该注解为@Configuration与@ComponentScan的组合注解,可以替代这两个注解。

在项目的开发中会使用Java配置和注解混合配置。何时使用Java配置或者注解配置呢?主要的原则是:全局配置使用Java配置(如:数据库相关配置、MVC相关配置),业务Bean的配置使用注解配置(如:@Component、@Repository、@Service、@Controller)。

3、@ComponentScan注解的使用

【实例】创建Java项目,在项目中使用@Repository、@Service注解。然后使用@ComponentScan注解自动扫描组件。实现获取用户信息业务,并在测试方法中显示用户信息。

(1)创建项目

创建Java项目,搭建项目结构,如下图:

使用Maven进行项目的构建,pom.xml文件的配置如下:

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring.version>5.2.3.RELEASE</spring.version>
</properties>

<dependencies>
    <!-- Spring框架 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
</dependencies>

(2)实体层(Entity层)

在Entity目录(实体层),创建用户信息实体类(UserInfo.java)。

package com.pjb.entity;

/**
 * 用户信息实体类
 * @author pan_junbiao
 **/
public class UserInfo
{
    private int userId; //用户ID
    private String userName; //用户姓名
    private String blogUrl; //博客地址
    private String remark; //备注

    //省略getter与setter方法...
}

(3)数据访问层(Dao层)

创建用户信息数据库访问接口(UserDao.java)。

package com.pjb.dao;

import com.pjb.entity.UserInfo;

/**
 * 用户信息数据库访问接口
 * @author pan_junbiao
 **/
public interface UserDao
{
    /**
     * 获取用户信息
     */
    public UserInfo getUserInfo();
}

创建用户信息数据库访问类(UserDaoImpl.java),并标识@Repository注解,实现UserDao接口,实现获取用户信息,模拟读取数据库获取数据方法。

package com.pjb.dao.impl;

import com.pjb.dao.UserDao;
import com.pjb.entity.UserInfo;
import org.springframework.stereotype.Repository;

/**
 * 用户信息数据库访问类
 * @author pan_junbiao
 **/
@Repository
public class UserDaoImpl implements UserDao
{
    /**
     * 获取用户信息
     */
    public UserInfo getUserInfo()
    {
        //获取用户信息(模拟读取数据库获取数据)
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(1);
        userInfo.setUserName("pan_junbiao的博客");
        userInfo.setBlogUrl("https://blog.csdn.net/pan_junbiao");
        userInfo.setRemark("您好,欢迎访问 pan_junbiao的博客");
        return userInfo;
    }
}

(4)业务逻辑服务层(Service层)

创建用户信息业务逻辑接口(UserService.java)。

package com.pjb.service;

import com.pjb.entity.UserInfo;

/**
 * 用户信息业务逻辑接口
 * @author pan_junbiao
 **/
public interface UserService
{
    /**
     * 获取用户信息
     */
    public UserInfo getUserInfo();
}

用户信息业务逻辑类(UserServiceImpl.java),并实现UserService接口。

package com.pjb.service.impl;

import com.pjb.dao.UserDao;
import com.pjb.entity.UserInfo;
import com.pjb.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 用户信息业务逻辑类
 * @author pan_junbiao
 **/
@Service
public class UserServiceImpl implements UserService
{
    @Autowired
    private UserDao userDao;

    /**
     * 获取用户信息
     */
    public UserInfo getUserInfo()
    {
        return userDao.getUserInfo();
    }
}

(5)Java配置类(Config层)

创建Java配置类(JavaConfig.java)。

package com.pjb.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * Java配置类
 * @author pan_junbiao
 **/
@Configuration
@ComponentScan({"com.pjb.dao","com.pjb.service"})
public class JavaConfig
{
}

代码说明:

在该类中使用@Configuration注解声明当前类是一个配置类;

使用@ComponentScan注解自动扫描包名下所有使用@Component、@Repository、@Service、@Controller注解的类,并注册为Bean。

@ComponentScan注解扫描多个包文件:

//方式一:
@ComponentScan({"com.pjb.dao","com.pjb.service"})

//方式二:
@ComponentScan("com.pjb.*")

(6)测试(Test层)

创建测试类(MyTest.java)。

import com.pjb.config.JavaConfig;
import com.pjb.entity.UserInfo;
import com.pjb.service.UserService;
import com.pjb.service.impl.UserServiceImpl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * 测试类
 * @author pan_junbiao
 **/
public class MyTest
{
    public static void main(String[] args)
    {
        //使用AnnotationConfigApplicationContext作为Spring容器
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);

        //获取声明配置的UserService的Bean
        UserService userService = context.getBean(UserServiceImpl.class);

        //执行业务逻辑方法,获取用户信息
        UserInfo userInfo = userService.getUserInfo();

        //打印结果
        System.out.println("用户编号:" + userInfo.getUserId());
        System.out.println("用户姓名:" + userInfo.getUserName());
        System.out.println("博客地址:" + userInfo.getBlogUrl());
        System.out.println("备注信息:" + userInfo.getRemark());
    }
}

代码说明:

使用AnnotationConfigApplicationContext可以实现基于Java的配置类(包括各种注解)加载Spring的应用上下文。避免使用application.xml进行配置。相比XML配置,更加便捷。

执行结果:

4、@Configuration注解和@Bean注解的使用

【实例】修改上述实例,使用@Configuration注解和@Bean注解。

(1)数据访问层(Dao层)

修改用户信息数据库访问类(UserDaoImpl.java),注释掉@Repository注解,表示没有使用@Repository注解声明Bean。

package com.pjb.dao.impl;

import com.pjb.dao.UserDao;
import com.pjb.entity.UserInfo;

/**
 * 用户信息数据库访问类
 * @author pan_junbiao
 **/
//表示没有使用@Repository注解声明Bean
//@Repository
public class UserDaoImpl implements UserDao
{
    /**
     * 获取用户信息
     */
    public UserInfo getUserInfo()
    {
        //获取用户信息(模拟读取数据库获取数据)
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(1);
        userInfo.setUserName("pan_junbiao的博客");
        userInfo.setBlogUrl("https://blog.csdn.net/pan_junbiao");
        userInfo.setRemark("您好,欢迎访问 pan_junbiao的博客");
        return userInfo;
    }
}

(2)业务逻辑服务层(Service层)

修改用户信息业务逻辑类(UserServiceImpl.java)。

1、注释掉@Service注解,表示没有使用@Service注解声明Bean。

2、注释掉@Autowired注解,表示没有使用@Autowired注解注入Bean。

3、添加UserDao对象的set方法(注意:一定要添加)

package com.pjb.service.impl;

import com.pjb.dao.UserDao;
import com.pjb.entity.UserInfo;
import com.pjb.service.UserService;

/**
 * 用户信息业务逻辑类
 * @author pan_junbiao
 **/
//表示没有使用@Service注解声明Bean
//@Service
public class UserServiceImpl implements UserService
{
    //表示没有使用@Autowired注解注入Bean
    //@Autowired
    private UserDao userDao;

    public void setUserDao(UserDao userDao)
    {
        this.userDao = userDao;
    }

    /**
     * 获取用户信息
     */
    public UserInfo getUserInfo()
    {
        return userDao.getUserInfo();
    }
}

(3)Java配置类(Config层)

修改Java配置类(JavaConfig.java)。

package com.pjb.config;

import com.pjb.dao.UserDao;
import com.pjb.dao.impl.UserDaoImpl;
import com.pjb.service.UserService;
import com.pjb.service.impl.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Java配置类
 * @author pan_junbiao
 **/
@Configuration
public class JavaConfig
{
    /**
     * 创建UserDao的Bean对象
     * 用于注入到UserService的Bean对象中
     */
    @Bean
    public UserDao userDao()
    {
        UserDaoImpl userDaoImpl = new UserDaoImpl();
        return userDaoImpl;
    }

    /**
     * 创建UserService的Bean对象
     * 方式一:
     * 使用@Bean注解的autowire属性,
     * Autowire.BY_TYPE表示通过类型进行自动装配
     */
    @Bean(autowire = Autowire.BY_TYPE)
    public UserService userService()
    {
        UserServiceImpl userServiceImpl = new UserServiceImpl();
        return userServiceImpl;
    }

    /**
     * 创建UserService的Bean对象
     * 方式二:
     * 注入UserDao的bean时候直接调用userDao()方法。
     */
    /*@Bean
    public UserService userService()
    {
        UserServiceImpl userServiceImpl = new UserServiceImpl();
        userServiceImpl.setUserDao(userDao());
        return userServiceImpl;
    }*/

    /**
     * 创建UserService的Bean对象
     * 方式三:
     * 直接将UserDao作为参数给userService()方法,
     * 在Spring容器中,只要容器中存在某个Bean,
     * 就可以在另外一个Bean的声明方法的参数中注入。
     */
    /*@Bean
    public UserService userService(UserDao userDao)
    {
        UserServiceImpl userServiceImpl = new UserServiceImpl();
        userServiceImpl.setUserDao(userDao);
        return userServiceImpl;
    }*/
}

执行结果:

5、@Bean注解注入对象的方式

方式一:

/**
 * 创建UserService的Bean对象
 * 方式一:
 * 使用@Bean注解的autowire属性,
 * Autowire.BY_TYPE表示通过类型进行自动装配
 */
@Bean(autowire = Autowire.BY_TYPE)
public UserService userService()
{
    UserServiceImpl userServiceImpl = new UserServiceImpl();
    return userServiceImpl;
}

@Bean注解提供的属性如下:

value:name属性的别名,在不需要其他属性时使用,也就是说value 就是默认值。

name:此bean 的名称,或多个名称,主要的bean的名称加别名。如果未指定,则bean的名称是带注解方法的名称。如果指定了,方法的名称就会忽略,如果没有其他属性声明的话,bean的名称和别名可能通过value属性配置。

autowire :此注解的方法表示自动装配的类型,返回一个Autowire类型的枚举,我们来看一下Autowire枚举类型的概念。

// 枚举确定自动装配状态:即,bean是否应该使用setter注入由Spring容器自动注入其依赖项。
// 这是Spring DI的核心概念
public enum Autowire {

  // 常量,表示根本没有自动装配。
  NO(AutowireCapableBeanFactory.AUTOWIRE_NO),
  // 常量,通过名称进行自动装配
  BY_NAME(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME),
  // 常量,通过类型进行自动装配
  BY_TYPE(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE);

  private final int value;
  Autowire(int value) {
    this.value = value;
  }
  public int value() {
    return this.value;
  }
  public boolean isAutowire() {
    return (this == BY_NAME || this == BY_TYPE);
  }
}

autowire的默认值为No,默认表示不通过自动装配。

方式二:

/**
 * 创建UserService的Bean对象
 * 方式二:
 * 注入UserDao的bean时候直接调用userDao()方法。
 */
@Bean
public UserService userService()
{
    UserServiceImpl userServiceImpl = new UserServiceImpl();
    userServiceImpl.setUserDao(userDao());
    return userServiceImpl;
}

在注入UserDao的bean时候直接调用userDao()方法。

方式三:

/**
 * 创建UserService的Bean对象
 * 方式三:
 * 直接将UserDao作为参数给userService()方法,
 * 在Spring容器中,只要容器中存在某个Bean,
 * 就可以在另外一个Bean的声明方法的参数中注入。
 */
@Bean
public UserService userService(UserDao userDao)
{
    UserServiceImpl userServiceImpl = new UserServiceImpl();
    userServiceImpl.setUserDao(userDao);
    return userServiceImpl;
}

直接将UserDao作为参数给userService()方法,这也是Spring容器提供的极好功能。在Spring容器中,只要容器中存在某个Bean,就可以在另外一个Bean的声明方法的参数中注入。

发布了377 篇原创文章 · 获赞 278 · 访问量 180万+

猜你喜欢

转载自blog.csdn.net/pan_junbiao/article/details/104594766