Spring @ComponentScan注释

时间:2020-01-09 10:44:32  来源:igfitidea点击:

Spring框架可以自动检测以@Component和其他构造型注释(如@ Repository,@ Service,@ Controller)注释的类。我们需要某种方法来告诉Spring在哪里寻找被这些注释之一注释的类。为此,我们可以使用Spring @ComponentScan注释,也可以指定要扫描的基本包。 Spring将扫描组件的基本包以及所有子包,并将它们注册为bean。

@ComponentScan与@Configuration注释一起使用以指定要扫描的软件包。由于bean是自动注册的,因此无需在配置类中使用@Bean注释标记的方法。使用@ComponentScan注释(用于自动注册bean)和@Autowired注释(用于自动注入依赖项),无需显式配置。

@ComponentScan注释与Spring XML配置中使用的<context:component-scan>元素相对应。

@ComponentScan,没有特定的软件包

如果未与@ComponentScan一起定义特定的程序包,则将从声明此注释的类的程序包中进行扫描。

例如,如果在com.theitroad.springexample.service软件包中包含Service类,在com.theitroad.springexample.dao软件包中具有DAO类,在com.theitroad.springexample软件包中具有AppConfig类,则子软件包将被扫描如果我们未使用@ComponentScan指定任何基本软件包。

Spring @ComponentScan示例

UserService介面

import java.util.List;
import com.theitroad.springexample.dto.User;

public interface UserService {
  public List<User> getUsers();
}

UserServiceImpl类

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.theitroad.springexample.dao.UserDAO;
import com.theitroad.springexample.dto.User;

@Service("userService")
public class UserServiceImpl implements UserService{
  @Autowired
  UserDAO userDAO;

  public List<User> getUsers() {
    return userDAO.getUsers();
  }
}

UserDAO界面

import java.util.List;
import com.theitroad.springexample.dto.User;

public interface UserDAO {
  public List<User> getUsers();
}

UserDAOImpl类

import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Repository;
import com.theitroad.springexample.dto.User;

@Repository
public class UserDAOImpl implements UserDAO {
  public List<User> getUsers() {
    System.out.println("In getUsers method, connect to DB and get data");
    List<User> userList = new ArrayList<User>();
    // Creating User instance locally
    User user = new User();
    user.setFirstName("John");
    user.setLastName("Wick");
    user.setAge(35);
    userList.add(user);
    return userList;
  }
}

DTO类(User.java)

public class User {
  private String firstName;
  private String lastName;
  private int age;
  public String getFirstName() {
    return firstName;
  }
  public String getLastName() {
    return lastName;
  }
  public int getAge() {
    return age;
  }
  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }
  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
  public void setAge(int age) {
    this.age = age;
  }	
}

配置类

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

@Configuration
@ComponentScan
public class AppConfig {

}

我们可以看到@ComponentScan没有指定基本包,因此扫描将从AppConfig类所在的包开始,所有子包也将被扫描。要运行此示例,请使用以下类

public class App {
  public static void main(String[] args) {
    AbstractApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

    UserService userService = context.getBean("userService", UserService.class);
    List<User> users = userService.getUsers();
    for(User user : users) {
      System.out.println("First Name- " + user.getFirstName());
      System.out.println("Last Name- " + user.getLastName());
      System.out.println("Age- " + user.getAge());
    }
    context.close();
  }
}

输出:

In getUsers method, connect to DB and get data
First Name- John
Last Name- Wick
Age- 35

用@ComponentScan指定参数

我们可以使用basePackages()(或者其别名value())指定基本软件包。

我们也可以使用basePackageClasses()指定类。指定类别的包装将被扫描。

1.使用@ComponentScan指定多个软件包

@Configuration
@ComponentScan(basePackages = {"com.theitroad.springexample", 
			       "com.theitroad.springexample.dao",
			       "com.theitroad.springexample.service"})
public class AppConfig {

}

2.尽管在上面显示的方案中仅指定父包就足够了,但是子包也将被递归扫描。

@Configuration
@ComponentScan(basePackages = "com.theitroad.springexample")
public class AppConfig {

}

3.如果不需要其他任何属性,我们甚至无需明确指定" basePackages"。

@Configuration
@ComponentScan("com.theitroad.springexample")
public class AppConfig {

}

4.我们也可以使用basePackageClasses()指定类,然后扫描该类所属的包。

@Configuration
@ComponentScan(basePackages = {"com.theitroad.springexample", 
                  "com.theitroad.springexample.dao"}, 
                  basePackageClasses = UserDAO.class)
public class AppConfig {

}

@ComponentScan带过滤器

我们还可以指定排除过滤器,并在@ComponentScan中包括过滤器。
使用excludeFilters,我们可以指定哪些类型不适合组件扫描。

使用includeFilters可以指定哪些类型适合进行组件扫描。

@ ComponentScan.Filter有五种可用的过滤器类型。它定义为Enum org.springframework.context.annotation.FilterType

  • 注释-过滤标记有给定注释的候选对象。

  • ASPECTJ-筛选匹配给定AspectJ类型模式表达式的候选对象。

  • ASSIGNABLE_TYPE-筛选可分配给给定类型的候选。

  • 自定义-使用给定的自定义TypeFilter实现过滤候选对象。

  • REGEX-过滤匹配给定正则表达式模式的候选。

这是一个排除类型为REGEX的过滤器的示例。

@Configuration
@ComponentScan(basePackages = {"com.theitroad.springexample", 
              "com.theitroad.springexample.dao"}, 
              basePackageClasses = UserDAO.class, 
              excludeFilters = @ComponentScan.Filter(type=FilterType.REGEX,
              pattern="com.theitroad.springexample.dto..*"))
public class AppConfig {

}

另一个使用FilterType.ASSIGNABLE_TYPE的示例

@Configuration
@ComponentScan(excludeFilters = @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE,
			   classes=UserService.class))
public class AppConfig {

}

这将排除任何实现UserService接口的类。