Spring注解开发源码解析

一:Spring IOC注解解析

1:@Configuration注解

下面是@Configuration注解的源码翻译部分:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
	/**
	 * 1、显式指定与此配置类关联的Spring bean定义的名称。如果未指定(常见情况),将自动生成bean名称。
	 * 2、只有通过组件扫描获取配置类或直接提供给{@link AnnotationConfigApplicationContext}时,才应用自定义名称。
	 * 3、如果配置类注册为传统的XML bean定义,那么bean元素的名称/id将优先。
	 * @return the specified bean name, if any
	 * @see org.springframework.beans.factory.support.DefaultBeanNameGenerator
	 */
	String value() default "";
}

具体看@Configuration的作用是什么?

//配置类:代替bean.xml配置文件
@Configuration
public class MainConfig {
    
    //给spring容器注册组件,类型就是返回值的类型Person,id为方法名person
    @Bean
    public Person person(){
        System.out.println("person方法执行了");
        return new Person();
    }

    //给spring容器注册组件,类型就是返回值的类型Dog,id为方法名dog
    @Bean
    public Dog dog(){
        person();
        System.out.println("dog方法执行了");
        return new Dog();
    }
}

public class MainTest {
    public static void main(String[] args) {
        //初始化容器
        ApplicationContext applicationContext
                = new AnnotationConfigApplicationContext(MainConfig.class);
		//获取容器中含有的组件名称
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for(String name:beanDefinitionNames){
            System.out.println(name);
        }
    }
}

MainTest类输出的结果:

//当初始化容器时,就会执行MainConfig类中的方法,并且发现person()方法只执行了一次,按照常理应该执行2次
person方法执行了
dog方法执行了
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
//容器中只有下面的三个组件
mainConfig
person
dog

问题:person()方法明明调用了两次,但是却只执行了一次,保证了@Bean的对象时单例,它是如何实现的?

原因:@Configuration这个注解的作用就是为MainConfig类加上Cglib动态代理,保证容器中的对象都是单例的

2:@ComponentScan注解

1、自动扫描组件

//将这个组件加入到IOC容器中
@Repository
public class BookDao {
}

public class BookService {
}

//将这个组件加入到IOC容器中
@Controller
public class BookController {
}

//配置类代替bean.xml配置文件
@Configuration
//将这个包下面的加了@Repository、@Service、@Controller、@Component注解的组件都加入容器中
@ComponentScan(value = "com.hh")
public class MainConfig {

    //将对象person放入spring容器中
    @Bean
    public Person person(){
        return new Person();
    }

    //将对象dog放入spring容器中
    @Bean
    public Dog dog(){
        return new Dog();
    }
}


public class MainTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext
                = new AnnotationConfigApplicationContext(MainConfig.class);

        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for(String name:beanDefinitionNames){
            System.out.println(name);
        }
    }
}

运行结果:

可以看出:这些组件加到了IOC容器中:而Service层的类BoorService由于没有使用@Service注解,没有被加入容器中
mainConfig
bookController
bookDao
person
dog

2:指定扫描规则

下面是@ComponentScan注解的部分源码,翻译了一下:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
	/**
	 *1、指示是否自动检测用{@code@Component}注释的类
	 */
	boolean useDefaultFilters() default true;

	/**
    1、指定哪些类型适合进行组件扫描。
    2、进一步将候选组件集从{@link#base packages}中的所有内容,缩小到与给定过滤器匹配的基本包中的所有内容。
    3、 注意,如果指定,这些过滤器将应用于默认过滤器之外。
    4、 指定的基包下与给定过滤器匹配的任何类型都将包括在内,即使它与默认过滤器不匹配(即没有用{@code@Component}注释)。
	 */
	Filter[] includeFilters() default {};

	/**
	 * 指定哪些类型不适合进行组件扫描。
	 */
	Filter[] excludeFilters() default {};

	/**
	 * 指定是否应为延迟初始化注册扫描的bean。
	 * 

Default is {@code false}; switch this to {@code true} when desired. */ boolean lazyInit() default false; /** 1、 声明要用作{@linkplain ComponentScan#includeFilters include filter} or {@linkplain ComponentScan#excludeFilters exclude filter}的类型过滤器。 */ @Retention(RetentionPolicy.RUNTIME) @Target({}) @interface Filter { /** * 1、要使用的过滤器类型。 *

Default is {@link FilterType#ANNOTATION}. * 默认FilterType.ANNOTATION */ FilterType type() default FilterType.ANNOTATION; @AliasFor("classes") Class[] value() default {}; @AliasFor("value") Class[] classes() default {}; String[] pattern() default {}; }

具体使用规则:

//配置类代替bean.xml配置文件
@Configuration
/**
 * 1、将这个包下面的添加了@Repository、@Service、@Controller、@Component注解的组件添加到容器中
 * 2、自定义扫描规则---使用过滤器排除一些组件:按照type = FilterType.ANNOTATION, classes = {Controller.class}来排除,
 * 3、自定义扫描规则---只扫描哪些组件:这个需要禁用掉默认的扫描规则才能生效
 */
@ComponentScan(value = "com.hh",
        excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})},
        includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Service.class})},useDefaultFilters = false)
public class MainConfig {

    //将对象person放入spring容器中
    @Bean
    public Person person(){
        return new Person();

    }

    //将对象dog放入spring容器中
    @Bean
    public Dog dog(){
        return new Dog();
    }
}

结果:

mainConfig
//只包含了@Service注解的组件
bookService
person
dog

3:自定义FilterType指定过滤规则

下面是 FilterType的源码:

public enum FilterType {

	/**
	 * 筛选用给定注释标记的候选项。
	 * @see org.springframework.core.type.filter.AnnotationTypeFilter
	 */
	ANNOTATION,

	/**
	 * 筛选可分配给给定类型的候选项。
	 * @see org.springframework.core.type.filter.AssignableTypeFilter
	 */
	ASSIGNABLE_TYPE,

	/**
	 * 筛选与给定AspectJ类型模式表达式匹配的候选项。
	 * @see org.springframework.core.type.filter.AspectJTypeFilter
	 */
	ASPECTJ,

	/**
	 * 筛选与给定正则表达式模式匹配的候选.
	 * @see org.springframework.core.type.filter.RegexPatternTypeFilter
	 */
	REGEX,

	/** 使用给定的自定义筛选候选
	 * {@link org.springframework.core.type.filter.TypeFilter} implementation.
	 */
	CUSTOM
}

具体使用规则:

//配置类代替bean.xml配置文件
@Configuration

//按照给定的类型来过滤 type = FilterType.ASSIGNABLE_TYPE,classes = {BookService.class}
@ComponentScan(value = "com.hh",
               includeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {BookService.class})},useDefaultFilters = false)
public class MainConfig {

    //将对象person放入spring容器中
    @Bean
    public Person person(){
        return new Person();
    }

    //将对象dog放入spring容器中
    @Bean
    public Dog dog(){
        return new Dog();
    }
}

 自定义FilterType来过滤:

public class MyTypeFilter implements TypeFilter {

    /**
     * metadataReader:读取到的当前正在扫描的类的信息
     * metadataReaderFactory:可以获取到其他任何类信息的
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
            throws IOException {
        // TODO Auto-generated method stub
        //获取当前类注解的信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //获取当前正在扫描的类的类信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //获取当前类资源(类的路径)
        Resource resource = metadataReader.getResource();

        String className = classMetadata.getClassName();
        System.out.println("--->"+className);
        if(className.contains("er")){
            return true;
        }
        return false;
    }
}
3:@Scope注解

下面是翻译后的@Scope注解的源码:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {
	/**
	 * Alias for {@link #scopeName}.
	 * @see #scopeName
	 */
	@AliasFor("scopeName")
	String value() default "";

	/**
	 1、指定用了Scope注解的组件/bean的作用域的名称。
	 2、 默认为空字符串,代表{@link ConfigurableBeanFactory#SCOPE_SINGLETON SCOPE_SINGLETON}.
	 * @see ConfigurableBeanFactory#SCOPE_PROTOTYPE
	 * @see ConfigurableBeanFactory#SCOPE_SINGLETON
	 * @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST
	 * @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION
	 * @see #value
	 */
	@AliasFor("value")
	String scopeName() default "";

	/**
	 * 1、指定组件是否应配置为作用域代理,如果应配置,则代理应基于接口还是基于子类。
	 * 2、默认为{@link ScopedProxyMode#DEFAULT},这通常表示除非在组件扫描指令级别配置了不同的默认值,否则不应创建作用域代理。
	 * 3、类似于Spring XML中的{@code}支持。
	 * @see ScopedProxyMode
	 */
	ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
}

具体使用规则:

@Configuration
@ComponentScan("com.hh")
public class MainConfig2 {

    /**
     * prototype:多实例的:ioc容器启动并不会去调用方法创建对象放在容器中。
     * 					每次获取的时候才会调用方法创建对象;
     * singleton:单实例的(默认值):ioc容器启动会调用方法创建对象放到ioc容器中。
     * 			以后每次获取就是直接从容器(map.get())中拿,
     * request:同一次请求创建一个实例
     * session:同一个session创建一个实例
     */
    @Scope("prototype")
    @Bean("person")
    public Person person(){
        System.out.println("person()方法执行了。。。。");
        return new Person();
    }
}

public class MainTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext
                = new AnnotationConfigApplicationContext(MainConfig2.class);

        System.out.println(applicationContext.getBean("person"));
        System.out.println(applicationContext.getBean("person"));
    }
}

结果:ioc容器启动并不会去调用方法创建对象放在容器中,每次获取的时候才会调用方法创建对象;

person()方法执行了。。。。
Person(name=null, age=null)
person()方法执行了。。。。
Person(name=null, age=null)
4:@Lazy注解
@Configuration
@ComponentScan("com.hh")
public class MainConfig2 {
    /**
     * 单实例bean:默认在容器启动的时候创建对象;
     * 懒加载:容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化;
     */
    @Lazy
    @Bean("person")
    public Person person(){
        System.out.println("person()方法执行了。。。。");
        return new Person();
    }
}

public class MainTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext
                = new AnnotationConfigApplicationContext(MainConfig2.class);
        System.out.println("IOC容器创建完成.....");
    }
}

结果:

IOC容器创建完成.....
5:@Import注解

@Import注解注解的源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
	/**
	 * {@link Configuration}, 
	 * {@link ImportSelector}, 
	 * {@link ImportBeanDefinitionRegistrar}
	 * or regular component classes to import.
	 */
	Class[] value();//这是一个数组形式
}

1:使用类名导入组件

@Data
public class Color {
	private String color;
}

@Data
public class Red{
}

@Configuration
@Import({Color.class, Red.class})
public class MainConfig2 {
    @Bean
    public Person person(){
        return new Person();
    }
}

容器中的组件为:

mainConfig2
com.hh.bean.Color
com.hh.bean.Red
person

2:ImportSelector

@Configuration
@Import({Color.class, Red.class,MyImportSelector.class})
public class MainConfig2 {
    @Bean
    public Person person(){
        return new Person();
    }
}

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        //需要导入类的全类名
        return new String[]{"com.hh.bean.Yellow","com.hh.bean.Blue"};
    }
}

结果:返回需要导入的组件的全类名数组;

mainConfig2
com.hh.bean.Color
com.hh.bean.Red
com.hh.bean.Yellow
com.hh.bean.Blue
person

3:ImportBeanDefinitionRegistrar

ImportBeanDefinitionRegistrar:手动注册bean到容器中

public class RainBow {
}

@Configuration
@Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class MainConfig2 {
    @Bean
    public Person person(){
        return new Person();
    }
}

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //判断容器中是否包含这个组件
        boolean definition1 = registry.containsBeanDefinition("com.hh.bean.Red");
        boolean definition2 = registry.containsBeanDefinition("com.hh.bean.Blue");
        if(definition1 && definition2){
            //指定Bean名
            RootBeanDefinition definition = new RootBeanDefinition(RainBow.class);
            //给容器中注册Bean
            registry.registerBeanDefinition("rainbow",definition);
        }
    }
}
6:FactoryBean

给容器中加入组件的方法:

@ComponentScan注解+@Controller、@Service、@Repository、@Component(局限,是自己写的类)
@Bean(导入第三方组件)
@Import 快速的给容器中导入一个组件
FactoryBean

二:Spring bean的生命周期

1:指定初始化和销毁方法
@Component
public class Car {
	public Car(){
		System.out.println("car constructor...");
	}
	
	public void init(){
		System.out.println("car ... init...");
	}
	
	public void destory(){
		System.out.println("car ... destory...");
	}
}

/**
 *  1、bean的生命周期由容器管理:创建---初始化---销毁
 *  2、初始化和销毁方法可以自定义
 *  3、
 *     初始化时机:对象创建完成,调用初始化方法
 *     对于单实例Bean的销毁时机:容器的关闭的时候
 *     对于多实例Bean:不会管理销毁方法
 */
@ComponentScan("com.hh.bean")
@Configuration
public class MainConfigOfLifeCycle {
    
    @Bean(initMethod ="init",destroyMethod = "destory")
    public Car car(){
        return new Car();
    }
}

//测试类
public class IOCTest_LifeCycle {
    @Test
    public void test01(){
        //创建ioc容器
        AnnotationConfigApplicationContext applicationContext
                = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成...");

        //关闭容器
        applicationContext.close();
    }
}
2:InitializingBean 和 DisposableBean接口
public interface InitializingBean {
   void afterPropertiesSet() throws Exception;
}

public interface DisposableBean {
	void destroy() throws Exception;
}
@Component
public class Cat implements InitializingBean,DisposableBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("初始化。。。。。");
    }
    @Override
    public void destroy() throws Exception {
        System.out.println("销毁。。。。。");
    }
}
3:使用 @PostConstruct与@PreDestroy

@PostConstruct注解:对象创建后调用标注了这个注解的方法

@PreDestroy注解:容器移除之前调用标注了这个注解的方法

//对象创建后调用标注了这个注解的方法
public @interface PostConstruct {
}
//容器移除之前调用标注了这个注解的方法
public @interface PreDestroy {
}
@Component
public class Dog  {
   //对象创建并赋值之后调用
   @PostConstruct
   public void init(){
      System.out.println("Dog....@PostConstruct...");
   }
   
   //容器移除对象之前
   @PreDestroy
   public void detory(){
      System.out.println("Dog....@PreDestroy...");
   }
}
4:BeanPostProcessor

BeanPostProcessor:bean的后置处理器,在初始化前后进行一些处理工作

public interface BeanPostProcessor {
   /**
    * 在初始化之前进行一些处理工作
    */
   Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

   /**
    * 在初始化之后进行一些处理工作
    */
   Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

   @Override
   public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean);
      return bean;
   }

   @Override
   public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean);
      return bean;
   }
}

容器中的组件在初始化之前和初始化之后都执行一些处理:

postProcessBeforeInitialization...cat=>com.hh.bean.Cat@105fece7
cat...init..
postProcessAfterInitialization...cat=>com.hh.bean.Cat@105fece7
car constructor...
postProcessBeforeInitialization...car=>com.hh.bean.Car@6b419da
car ... init...
postProcessAfterInitialization...car=>com.hh.bean.Car@6b419da

三:自动装配

1:@Autowired、@Qualifier、@Primary
@Data
@Repository //默认使用类名首字母小写作为组件id,bookDao
public class BookDao {
    private String lable = "1";
}

@Configuration
@ComponentScan({"com.hh.service","com.hh.dao","com.hh.controller","com.hh.bean"})
public class MainConifgOfAutowired {
    //向容器中再加入一个组件bookDao2
	@Bean("bookDao2")
	public BookDao bookDao(){
		BookDao bookDao = new BookDao();
		bookDao.setLable("2");
		return bookDao;
	}
}


@Service
@Data
public class BookService {
    /**
     * 1、默认按照类型(ByType)去容器中找对应的组件
     * 2、如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找 (bookDao)
     * 3、@Qualifier("bookDao"):使用@Qualifier指定需要装配的组件的id
     * 4、@Primary:让Spring进行自动装配的时候,默认使用首选的bean
     * 5、自动装配默认一定要将属性赋值好,没有就会报错;可以使用 @Autowired(required=false);
     */
    @Qualifier("bookDao2")
    @Autowired
    private BookDao bookDao;

    public void print(){
        System.out.println(bookDao);
    }
}
2:@Resource(JSR250)、@Inject(JSR330)

java规范的注解

@Service
public class BookService {
    /**
     * 1、默认按照属性名称到容器中找对应的组件进行注入(byName:bookDao)
     * 2、可以指定组件的名称 @Resource(name="bookDao2")
     * 3、没有required=false的功能,@Primary功能
     */
    @Resource(name="bookDao2")
    private BookDao bookDao;
}
@Service
public class BookService {
    /**
     * 1、@Inject:需要导入javax.inject的包,和Autowired的功能一样
     * 2、没有required=false的功能
     */
    private BookDao bookDao;
}
3:@Autowired标在方法、构造器、参数上

1:默认情况下,加在容器中的组件,在容器启动时就会调用无参构造函数来创建对象,然后初始化,把@Autowired标注在方法上,该方法如果有参数(组件),会使用autowired的方式(byType)在容器中查找是否有该组件

@Component
public class Boss {
   private Car car;
   //标注在方法上,该方法如果有参数(组件),会使用autowired的方式(byType)在容器中查找是否有该组件
   @Autowired
   public void setCar(Car car) {
      this.car = car;
   }
}

2:标注在带参构造函数上,如果组件只有一个有参构造器,这个有参构造器的@Autowired可以省略,参数位置的组件可以自动从容器中获取。

@Component
public class Boss {
   private Car car;
   
   //构造器要用的组件,从容器中获取
   public Boss(Car car){
      this.car = car;
      System.out.println("Boss...有参构造器");
   }
}

3:标注在参数上

@Component
public class Boss {
   private Car car;
   public void setCar(@Autowired Car car) {
      this.car = car;
   }
}

4:标注在方法上:@Bean+方法参数;参数从容器中获取;默认不写@Autowired效果是一样的;都能自动装配

@Configuration
@ComponentScan({"com.hh.service","com.hh.dao","com.hh.controller","com.hh.bean"})
public class MainConifgOfAutowired {
   //@Bean标注的方法创建对象的时候,方法参数的值从容器中获取
   @Bean
   public Color color(Car car){
      Color color = new Color();
      return color;
   }
}
4:自定义组件想使用Spring容器底层的组件

自定义组件实现xxxAware;在创建对象的时候,会调用接口规定的方法注入相关组件;Aware;

把Spring底层一些组件注入到自定义的Bean中;

@Data
@Component
public class Red implements ApplicationContextAware, BeanNameAware {
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("当前IOC容器:"+applicationContext);
        this.applicationContext = applicationContext;
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("当前Bean的名称:"+name);
    }
}

本文是关于spring注解开发的相关内容,希望可以帮到初学spring的小伙伴哦!

Spring注解开发源码解析_第1张图片

你可能感兴趣的:(Spring框架,spring,java,mysql)