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接口的类。