Spring @ComponentScan注释
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接口的类。

