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

来源:互联网 发布:苏州网络教育多少钱 编辑:程序博客网 时间:2024/06/03 23:45


   在没有引入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·在使用注解后:

@Componentpublic 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@Componentpublic @interface MyComponent {String value() default "";}


B java普通类:

package com.dynamic.spring.annotations;@MyComponentpublic 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.xsdhttp://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扫描到,并注入容器内。











原创粉丝点击