Spring - @ComponentScan用法及手写简单实现

本文详细介绍了Spring框架中@ComponentScan注解的使用,包括默认扫描规则以及如何通过basePackages和includeFilters属性进行自定义配置。通过示例展示了如何通过这个注解将@Service、@Controller、@Component、@Repository注解的类加载到Spring容器。同时,文章还揭示了在实际应用中如何手写类似功能的实现,进一步加深了对@ComponentScan工作原理的理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

@ComponentScan:默认扫描与当前类所在包下的带有@Service、@Controller、@Component、@Repository 注解修饰的类装入到Spring容器中。

package com.demo.test;

import org.springframework.stereotype.Controller;

@Controller
public class TestController {
}
package com.demo.test;

import org.springframework.stereotype.Service;

@Service
public class TestService {
}
package com.demo.test;

import org.springframework.stereotype.Repository;

@Repository
public class TestRepository {
}
package com.demo.test;

import org.springframework.stereotype.Component;

@Component
public class TestComponent {
}

首先写了四个组件,分别用了四个不同的注解。

接下来,写@ComponentScan修饰的类。

package com.demo.test;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;


@ComponentScan(basePackages = {"com.demo.test"},
        includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})},
        useDefaultFilters = false)
public class TestConfig {
}

basePackages:设定扫描的包。

includeFilters:设定过滤器。

@Filter的type设定过滤注解,本文中classes设定过滤Controller和Service的Class对象

useDefaultFilters:设定false。与includeFilters联合使用,表示只装配classes给出的Class对象标注的类

 

最后再写测试类:

package com.demo.test;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestDemo2 {

    public static void main(String[] args) {
        // 可以基于配置类创建应用上下文
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestConfig.class);
        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}

 AnnotationConfigApplicationContext:可以基于配置类创建应用上下文。

getBeanDefinitionNames():获得在spring容器中注册的bean的名字。

 

控制台输出:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
testConfig
testController
testService

 


手写简单实现:

    private List<String> classNames = new ArrayList<>();
    private Map<String, Object> ioc = new HashMap<>();
    private void doScanner(String packageName) {
        URL url = getClass().getClassLoader().getResource(packageName.replaceAll("\\.", "/"));
        File dir = new File(Objects.requireNonNull(url).getFile());
        for (File file : Objects.requireNonNull(Objects.requireNonNull(dir).listFiles())) {
            if (file.isDirectory()) {
                doScanner(packageName + "." + file.getName());
            }
            String className = packageName + file.getName().replace(".class", "");
            classNames.add(className);
        }
    }

    private String toLowerCaseOfFirstCharacter(String str) {
        char[] chars = str.toCharArray();
        chars[0] += 32;
        return String.valueOf(chars);
    }

    private void doInstance() {
        for (String className : classNames) {
            try {
                Class<?> cls = Class.forName(className);
                if (cls.isAnnotationPresent(MyController.class)) {
                    ioc.put(toLowerCaseOfFirstCharacter(className), cls.newInstance());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值