`
raymond.chen
  • 浏览: 1437407 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

手动创建或者扫描Bean并注册到Spring容器

 
阅读更多

使用方式:

       1、借助 @Import 注解类,创建ImportBeanDefinitionRegistrar的子类,手动构造BeanDefinition对象并注册到容器

       2、借助BeanFactoryPostProcessor接口类,通过ClassPathBeanDefinitionScanner类扫描并注册类到容器

       3、借助 @Import 注解类,创建ImportBeanDefinitionRegistrar的子类,通过ClassPathBeanDefinitionScanner类扫描并注册类到容器

 

一、通过创建 ImportBeanDefinitionRegistrar 的子类实现

public class User {
	private String username;
	private String password;
	
	public String getUsername() {
		return username;
	}
	
	public void setUsername(String username) {
		this.username = username;
	}
	
	public String getPassword() {
		return password;
	}
	
	public void setPassword(String password) {
		this.password = password;
	}
}


/**
 * 通过创建 ImportBeanDefinitionRegistrar 的子类实现手动将bean注入到Spring容器中。
 *		在方法registerBeanDefinitions中构造BeanDefinition对象,并调用BeanDefinitionRegistry的registerBeanDefinition方法注册
 * 		然后通过@Import注解导入到Spring容器中。
 */
public class MapperImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware{
	private ResourceLoader resourceLoader;
    
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
    	registerUserBean(registry);  	
    }
    
    private void registerUserBean(BeanDefinitionRegistry registry){
    	if(!registry.containsBeanDefinition(User.class.getSimpleName())){
	    	BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
	    	
	    	GenericBeanDefinition beanDefinition = (GenericBeanDefinition)builder.getRawBeanDefinition();
	    	beanDefinition.setBeanClass(User.class);
	    	beanDefinition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
	    	
                //设置目标Bean的属性值
	    	beanDefinition.getPropertyValues().add("username", "abc");
	    	beanDefinition.getPropertyValues().add("password", "123");
	    	
	    	registry.registerBeanDefinition(User.class.getSimpleName(), beanDefinition);
    	}
    }
    
    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
    	this.resourceLoader = resourceLoader;
    }
}


/**
 * CommandLineRunner:
 * 		用于在应用程序启动前执行某些动作。
 * 		在所有Spring Beans都初始化之后,SpringApplication.run()之前执行。
 * 		如果存在多个CommandLineRunner的实现类,可以使用@Order注解来排序。
 */
@SpringBootApplication()
@Import({MapperImportBeanDefinitionRegistrar.class})
public class Main implements CommandLineRunner {
	@Autowired
	private User user;
	
	public static void main(String[] args){
		SpringApplication.run(Main.class, args);
	}
	
	@Override
	public void run(String... args) throws Exception {
		System.out.println(user.getUsername() + ", " + user.getPassword());
	}
}

 

二、通过创建 BeanFactoryPostProcessor 的子类,并结合ClassPathBeanDefinitionScanner类实现

      BeanFactoryPostProcessor: 在Bean初始化之前Spring容器会回调该类的postProcessBeanFactory方法。

      ClassPathBeanDefinitionScanner:将指定包下的类通过一定规则过滤后将Class信息包装成 BeanDefinition 的形式注册到IOC容器中。

/**
 * 自定义注解类
 */
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Mapper {
	 String value() default "";
}


/**
 * 接口类
 */
public interface CountryMapper {
	void show();
}


/**
 * 接口的实现类,该类用自定义注解@Mapper进行标注
 */
@Mapper
public class CountryMapperImpl implements CountryMapper {
	@Override
	public void show(){
		System.out.println("invoke show...");
	}
}


/**
 * BeanFactoryPostProcessor的子类
 * 		在Bean初始化之前Spring容器会回调该类的 postProcessBeanFactory 方法
 */
@Component
public class MapperBeanFactoryPostProcessor implements BeanFactoryPostProcessor, ApplicationContextAware {
	private ApplicationContext applicationContext;
	
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}
	
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
	    //扫描满足特定规则的类,并注册到容器中
		MapperClassPathBeanDefinitionScanner scanner = new MapperClassPathBeanDefinitionScanner((BeanDefinitionRegistry)beanFactory);
		scanner.setResourceLoader(this.applicationContext);
		scanner.registerDefaultFilters();
		scanner.scan(MapperClassPathBeanDefinitionScanner.BASE_PACKAGES);
	}
}


public class MapperClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner{
	public static final String BASE_PACKAGES = "com.seasy.springboottest";

	public MapperClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
        super(registry);
    }
	
	public void registerDefaultFilters() {
		//默认:根据指定注解类@Mapper过滤出满足条件的类
		TypeFilter typeFilter = new AnnotationTypeFilter(Mapper.class);
		
		//根据指定的类(包括子类和接口类)过滤出满足条件的类
//		TypeFilter typeFilter = new AssignableTypeFilter(CountryMapperImpl.class);
//		TypeFilter typeFilter = new AssignableTypeFilter(CountryMapper.class);
		
        this.addIncludeFilter(typeFilter);
    }
	
	@Override
	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		return super.doScan(basePackages);
	}
	
	@Override
	protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
		return super.isCandidateComponent(beanDefinition) 
			&& beanDefinition.getMetadata().hasAnnotation(Mapper.class.getName());
	}
}


@SpringBootApplication()
public class Main implements CommandLineRunner {
	@Autowired
	private CountryMapper countryMapper;
	
	public static void main(String[] args){
		SpringApplication.run(Main.class, args);
	}
	
	@Override
	public void run(String... args) throws Exception {
		countryMapper.show();
	}
}

 

三、通过FactoryBean和Spring代理创建

/**
 * 自定义注解类
 */
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Mapper {
	 String value() default "";
}


//创建接口类,并用自定义注解类标注
@Mapper
public interface RoleMapper{
	public void printRole();
}

@Mapper
public interface UserMapper{
	public void print();
}

/**
 * 自定义拦截器
 */
public class CustomMethodInterceptor implements MethodInterceptor{
	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		
		Object object = null;
		
		//接口没有对应的实现类,不能直接调用 invocation.proceed() 方法
        //object = invocation.proceed();
		
		//在此处编写业务逻辑
		//......

		System.out.println(invocation.getMethod().getDeclaringClass().getName() + ": " + invocation.getMethod().getName());
        
		stopWatch.stop();
        System.out.println("执行时间:" + stopWatch.getTotalTimeMillis() + "ms");
        return object;
	}
}

/**
 * 工厂Bean:通过Spring代理工厂创建代理类
 */
public class ScannerFactoryBean implements FactoryBean<Object>{
	private ProxyFactory factory;
	private String interfaceClassName;

	public void setInterfaceClassName(String interfaceClassName) {
		this.interfaceClassName = interfaceClassName;
		
		try {
			factory.setInterfaces(Class.forName(interfaceClassName));
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	public ScannerFactoryBean(){
		factory = new ProxyFactory(); //Spring代理工厂
	    factory.addAdvice(new CustomMethodInterceptor());
	}
	
	@Override
	public Object getObject() throws Exception {
		return factory.getProxy();
	}
	
	@Override
	public Class<?> getObjectType() {
		try {
			if(StringUtils.hasText(interfaceClassName)){
				return Class.forName(interfaceClassName);
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	@Override
	public boolean isSingleton() {
		return true;
	}
}

/**
 * 自定义BeanDefinition扫描器
 */
public class ScannerClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner{
	private ScannerFactoryBean scannerFactoryBean = new ScannerFactoryBean();
	
	public ScannerClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
        super(registry);
    }
	
	@Override
	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
		
		ScannedGenericBeanDefinition beanDefinition;
		for(BeanDefinitionHolder holder : beanDefinitions){
			beanDefinition = (ScannedGenericBeanDefinition) holder.getBeanDefinition();
			if(beanDefinition.getMetadata().isInterface()){ //是接口类
				//添加BeanClass的属性值
				beanDefinition.getPropertyValues().add("interfaceClassName", beanDefinition.getBeanClassName());

				beanDefinition.setBeanClass(scannerFactoryBean.getClass()); //通过工厂Bean获取Bean对象
			}
		}
		
		return beanDefinitions;
	}
	
	/**
	 * 是候选组件
	 */
	@Override
	protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
		AnnotationMetadata metadata = beanDefinition.getMetadata();
		
		//isIndependent独立的、isConcrete具体的、isInterface接口
		return metadata.isIndependent() && (metadata.isConcrete() || metadata.isInterface());
	}
}

public class ScannerImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar{
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
    	//BeanDefinition扫描器
    	ClassPathBeanDefinitionScanner scanner = new ScannerClassPathBeanDefinitionScanner(registry);
    	scanner.addIncludeFilter(new AnnotationTypeFilter(Mapper.class)); //基于注解类进行扫描过滤
    	scanner.scan("com.seasy.springboottest");
    }
}

/**
 * 配置类
 */
@Configuration
//通过导入的方式把实例加入SpringIOC容器中
@Import(value = {ScannerImportBeanDefinitionRegistrar.class})
public class ScannerConfig {

}

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Main.class)
public class ScannerTest {
	@Test
	public void test3()throws Exception{
		//基于配置类加载Spring的应用上下文
        AnnotationConfigApplicationContext applicationContext 
        	= new AnnotationConfigApplicationContext(ScannerConfig.class);
        
        UserMapper userMapper = (UserMapper)applicationContext.getBean("userMapper");
        userMapper.print();
        
        RoleMapper roleMapper = (RoleMapper)applicationContext.getBean("roleMapper");
        roleMapper.printRole();
	}
}

  

RuntimeBeanReference

        一个bean可能需要依赖其他的bean,而在Spring的解析阶段,其实容器中是没有依赖的Bean的实例的。为了表示这个被依赖的bean,在解析到依赖的Bean的时侯,解析器会依据依赖bean的name创建一个RuntimeBeanReference对像,将这个对像放入BeanDefinition的MutablePropertyValues中。

 

        reference = new RuntimeBeanReference("otherBeanName");

        beanDefinition.getPropertyValues().addPropertyValue("referBeanName", reference);

 

        在创建Bean时,需要将依赖解析成真正的在Spring容器中存在的Bean。这是在getBean时由AbstractAutowireCapableBeanFactory在applyPropertyValues方法中通过BeanDefinitionValueResolver来实现的。BeanDefinitionValueResolver将真正的依赖bean和referBeanName关联起来。

 

 

 

分享到:
评论

相关推荐

    41. Spring Boot 使用Java代码创建Bean并注册到Spring中【从零开始学Spring Boot】

    在本篇博文中,我们将深入探讨如何在Spring Boot应用中使用Java代码来创建Bean并将其注册到Spring容器中。这是Spring Boot的核心特性之一,它使得我们能够以编程方式管理对象,而无需XML配置。让我们逐步解析这个...

    spring自动扫描和管理Bean的示例

    在Spring框架中,自动扫描和管理Bean是一种便捷的方式,它允许开发者无需显式地在配置文件中声明每个Bean,而是让Spring容器自动发现并管理应用中的组件。这一特性极大地简化了Spring应用的配置,提高了开发效率。...

    mybatis注册到spring容器代码

    - 使用`PlatformTransactionManager`接口的实现,如`DataSourceTransactionManager`,并将其注册到Spring容器中。 5. **扫描Mapper接口** - 通过`MapperScannerConfigurer`或`@MapperScan`注解,扫描包含MyBatis ...

    自定义注解得使用,模拟spring通过注解方式创建bean实例

    这样,我们就创建了一个简单的注解处理器,它可以扫描指定包下所有带有`MyComponent`注解的类,并将它们注册为Spring的bean,bean的名称由注解的`value`属性决定。 最后,为了让Spring知道并执行我们的`...

    模拟Spring的IoC容器实现注解自动装配

    IoC容器是通过扫描应用程序上下文来发现所有需要管理的bean,并根据bean定义来创建和初始化这些bean。在Spring中,bean可以通过XML配置、Java配置或者注解进行定义。在模拟实现时,我们可以创建一个`BeanDefinition`...

    Java中Spring获取bean方法小结

    - 避免过度使用`getBean()`:频繁使用`getBean()`可能导致代码过于紧密地耦合于Spring容器,降低代码的可读性和可测试性。 总结,Spring框架通过BeanFactory和ApplicationContext提供了灵活的方式来管理和获取Bean...

    Spring扫描器—spring组件扫描使用详解

    它会遍历指定包及其子包下的所有类,寻找带有特定注解(如@Service、@Component、@Repository、@Controller等)的类,并将这些类实例化为Spring容器中的bean。通过这种方式,我们可以避免手动编写大量的XML配置,...

    使用java类配置Bean

    当Spring容器加载这个配置类时,它会调用这些@Bean注解的方法,生成Bean实例并将其注册到IoC容器中。 在SIA实战项目中,我们可能会看到类似这样的代码片段: ```java @Configuration public class AppConfig { @...

    spring 扫描jar maven 打包

    扫描机制允许开发者声明类为Spring管理的bean,无需在XML配置文件中手动注册。Spring通过`@Component`、`@Service`、`@Repository`和`@Controller`等注解标记类,然后使用`@ComponentScan`注解来指定哪些包应该被...

    Spring系列面试题129道(附答案解析)

    其核心思想是反转控制(IoC),即控制权由应用代码转移到了Spring容器。 10、什么是依赖注入? 依赖注入(DI)是一种设计模式,它允许一个对象通过构造器、工厂方法的参数或属性来定义它们对其他对象的依赖关系,...

    springDemo.zip

    当Spring容器遇到`@Bean`注解的方法时,它会执行该方法,将返回的对象添加到bean定义中,并根据需要进行依赖注入。你可以通过`@Bean`注解的参数来指定依赖关系,或者使用`@Autowired`注解来自动装配。 例如: ```...

    SpingIOC注入实例化bean

    在传统的编程模式中,开发者需要手动创建和管理对象,而在Spring IOC中,这个过程被反转,由Spring容器负责对象的创建、初始化、装配以及管理,开发者只需声明对象间的依赖,无需关心具体的实例化过程。 1. **Bean...

    mybatis-spring-1.3.3.jar官方下载

    3. **MapperScannerConfigurer**:这个类用于扫描指定包下的 Mapper 接口,并自动将其注册到 Spring 容器中,这样就可以通过依赖注入的方式直接使用这些接口。 4. **MapperFactoryBean**:它是 Spring 的 ...

    扩展Spring—使用Annotation将配置资源注入到Bean中

    `@Bean`方法返回的对象将被注册为Spring容器中的一个Bean。 7. **属性注入** `@Value`注解可以用来注入基本类型或者从属性文件中读取的值。例如,`@Value("${property.name}")`可以从`application.properties`文件...

    java模拟spring ioc

    Spring通过容器管理对象及其依赖,使得开发者无需手动创建和配置对象,而是由Spring来负责。 **控制反转(Inversion of Control,IOC)** 是DI的另一种表述方式,核心思想是将对象的创建和管理权交给框架或容器,而...

    springAOP核心组件分析.pdf

    AnnotationAwareAspectJAutoProxyCreator实现了这个接口,从而使得Spring容器在创建bean之后可以进行AOP相关的处理。它主要负责分析容器中的bean,寻找合适的切面,并将这些切面织入到目标bean中去。 后置处理器的...

    示例代码:自定义注解,使用ImportBeanDefinitionRegistrar自动加载

    在上述代码中,我们扫描了指定包路径下所有标记了`@MyComponent`注解的类,并将它们作为Bean定义注册到Spring容器中。 现在,我们来看看压缩包内的文件: 1. `pom.xml`:这是Maven项目的核心配置文件,它包含了...

    SpringBoot之Bean的使用及处理

    Spring容器会根据这些定义创建Bean的实例,并负责其生命周期。 1. **Bean的声明**:有两种主要方式声明Bean,一种是使用XML配置,另一种是使用注解。在Spring Boot中,更倾向于使用注解,如@Component、@Service、@...

    springmvc+spring4+mybatis3整合,自动扫描

    在实际开发中,自动扫描功能可以帮助我们避免手动注册每个Mapper接口,只需指定正确的包名,Spring就会自动查找并管理这些接口,大大提高了开发效率。同时,合理地整合和配置这三个框架,可以构建出一个灵活、可扩展...

    spring ioc.rar

    DI允许我们声明bean间的依赖关系,而无需在代码中手动创建或查找依赖对象。Spring容器会根据配置自动装配bean。这可以通过构造函数注入、setter方法注入或者字段注入来实现。 4. **Scope**: Spring提供了多种bean的...

Global site tag (gtag.js) - Google Analytics