《Spring IOC 学习——注解工作机制》

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012788601/article/details/73848916


   在没有引入spring框架前,在类与类之间的调用关系通过new关键字进行实例化对象,进而调用对象的方法或者属性。在引入spring框架后,我们开始使用spring容器进行IOC注入,在spring的配置文件applicationContext.xml文件里,配置相应类的bean节点,在不配置懒加载bean节点的前提下,当配置文件applicationContext加载后,会自动实例化所有的singletonbean并缓存在容器中供我们类的调用。再后来,我们不再在xml文件中配置bean节点,而是配置<context:component-scan/>标签自动扫描包,通过注解的方式,被spring容器进行管理。


   现在我来简单描述一下这三个过程:

      1· 没有引入spring之前:

HelloWorld a=new HelloWorld();

      2·在引入Spring容器后,在applicationContext.xml文件里,配置类HelloWorld节点,

<beanid="helloWorld"class="com.dynamic.study1.HelloWorld"></bean>

      3·在使用注解后:

@Component
public class HelloWorld{}

这三个声明方式虽然变了,但是原理还是一样的。

2的过程中,是通过反射机制动态加载的类HelloWorld,其实质和new实例化是一样的,即:

Class t=Class.forName("package.A");  
t.newInstance();  

A a = new A();
实现的效果是一致的。所以说1和2的变化过程实质是一样的。

那在23的变化过程中,是怎么工作机制法呢?换句话说,spring注解是如何工作的呢?Spring是如何读取注解信息,并注入到bean容器中的?

先来看以下demo

A 自定义注解:

package com.dynamic.spring.annotations;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface MyComponent {
	String value() default "";
}


B java普通类:

package com.dynamic.spring.annotations;

@MyComponent
public class User {
	public User(){
		System.out.println("the User class.......");
	}
}


Spring配置文件applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

<!-- 配置自动扫描包 -->
<context:component-scan base-package="com.dynamic.spring.annotations"></context:component-scan>

</beans>

D 客户端:

package com.dynamic.spring.annotations;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
	public static void main(String[] args){
		ApplicationContext atc=new ClassPathXmlApplicationContext("applicationContext.xml");	
		atc.getBean(User.class);
	}

}

执行这个例子,就会发现,自定义注解@MyComponentspring容器加载进来了。

执行结果:


解析:为什么自定义的注解也能够像@Service,@Respository等注解被spring的配置文件扫描到?

查看Spring的源码会发现,Spring是使用ClassPathScanningCandidateComponentProvider扫描package,

这个类的 registerDefaultFilters 方法有这样几行代码:

/**
	 * Register the default filter for {@link Component @Component}.
	 * <p>This will implicitly register all annotations that have the
	 * {@link Component @Component} meta-annotation including the
	 * {@link Repository @Repository}, {@link Service @Service}, and
	 * {@link Controller @Controller} stereotype annotations.
	 * <p>Also supports Java EE 6's {@link javax.annotation.ManagedBean} and
	 * JSR-330's {@link javax.inject.Named} annotations, if available.
	 *
	 */
	@SuppressWarnings("unchecked")
	protected void registerDefaultFilters() {
		this.includeFilters.add(new AnnotationTypeFilter(Component.class));
		ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
		try {
			this.includeFilters.add(new AnnotationTypeFilter(
				((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
			logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
		}
		catch (ClassNotFoundException ex) {
			// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
		}
		try {
			this.includeFilters.add(new AnnotationTypeFilter(
				((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
			logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
		}
		catch (ClassNotFoundException ex) {
			// JSR-330 API not available - simply skip.
		}

}

这里就会发现Spring在扫描类信息的使用只会判断被@Component注解的类,所以任何自定义的注解只要带上@Component(当然还要有Stringvalue() default"";的方法,因为Spring的Bean都是有beanName唯一标示的),都可以被Spring扫描到,并注入容器内。











猜你喜欢

转载自blog.csdn.net/u012788601/article/details/73848916
今日推荐