(一)spring的bean注册
Spring框架中支持了两种不同形式的IOC容器初始化方式,一种是基于XML的容器初始化,另外一种是基于注解的初始化方式,初始化容器时使用的具体初始化类不同。
基于xml的方式:
ClasspathXmlApplicationContext
基于annotation的方式:
AnnotationConfigApplicationContext
他们都是AbstractApplicationContext的子类,在该类中定义了基于xml和annotation初始化容器及注册bean的公共流程,后面文章会具体分析其底层源码实现。下面先体验一下基于xml和annotation的bean注册方式。
基于xml的bean配置方式已经不再流行,这里简单介绍,能看懂代码就行。
一 基于xml的方式
1 示例bean
1 package demo.ioc.xml; 2 3 public class Person { 4 private String uuid; 5 6 public String getUuid() { 7 return uuid; 8 } 9 10 public void setUuid(String uuid) { 11 this.uuid = uuid; 12 } 13 14 @Override 15 public String toString() { 16 return "Person{" + 17 "uuid='" + uuid + '\'' + 18 '}'; 19 } 20 }
2 xml配置
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 5 <!-- 指定bean的ID以及bean对应的类型--> 6 <bean id="person" class="demo.ioc.xml.Person"> 7 <!-- 指定bean的属性名以及属性值, 此处使用基础属性 8 也可以使用引用类型属性,来引用另外一个bean --> 9 <property name="uuid" value="123"></property> 10 </bean> 11 </beans>
3 测试
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestMain { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Person person = context.getBean("person", Person.class); System.out.println(person); } }
输出:Person{uuid='123'}
二 基于annotation的方式
基于注解的bean配置方式,现在是主流,接下来详细介绍
(1) 基于@Component
1 示例bean
package demo.ioc.annotation.component; import org.springframework.stereotype.Component; @Component public class Person { private String uuid; public String getUuid() { return uuid; } public void setUuid(String uuid) { this.uuid = uuid; } @Override public String toString() { return "Person{" + "uuid='" + uuid + '\'' + '}'; } }
2 测试
package demo.ioc.annotation.component; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestMain { public static void main(String[] args) { // ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); ApplicationContext context = new AnnotationConfigApplicationContext(demo.ioc.annotation.component.Person.class); Person person = context.getBean("person", Person.class); System.out.println(person); } }
输出:Person{uuid='null'}
可以看到相比xml配置方式,配置更加简单,但是没有办法注入属性值
3 注解解析
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package org.springframework.stereotype; 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; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Component {
// 生成bean的名称,相当于xml配置文件的id,默认名称是目标Bean的Class类型第一个字符小写,例如Person的默认Bean名称是person String value() default ""; }
@Component是spring的基础注解,使用该注解标注的类,表示spring的IOC容器会在适当的时机实例化该类,并交由IOC容器管理,因此我们就不用显示实例化该类。
(2)基于@Configuration和@Bean
1 示例Bean
package demo.ioc.annotation.configuration;
import java.util.UUID;
public class Person {
private String uuid;
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
@Override
public String toString() {
return "Person{" +
"uuid='" + uuid + '\'' +
'}';
}
private void init() {
uuid = UUID.randomUUID().toString();
System.out.println(uuid);
}
private void destroy() {
uuid = null;
System.out.println(uuid);
}
}
2 配置类
package demo.ioc.annotation.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BeanConfig {
@Bean(initMethod = "init", destroyMethod = "destroy")
public Person getPerson() {
Person person = new Person();
person.setUuid("1234");
return person;
}
}
3 测试
package demo.ioc.annotation.configuration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
public class TestMain {
public static void main(String[] args) {
// ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
AbstractApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
demo.ioc.annotation.configuration.Person person = context.getBean("getPerson", Person.class);
System.out.println(person);
context.close();
}
}
输出:
61ab9f03-544e-41a2-9ab3-767e02cf533e
Person{uuid='61ab9f03-544e-41a2-9ab3-767e02cf533e'}
null
该方法相当于@Component注解,能够设置属性,更加灵活。
4 注解解析
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package org.springframework.context.annotation; 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; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Configuration {
//配置类的名称 String value() default ""; }
可以看到@Configuration注解本身也使用了@Component,表示该类也由Spring的IOC负责实例化,不过标注了@Configuration注解的类还允许使用@Bean
标注非private以及final方法,标注之后,容器在适当的时候,会扫描配置类,按照标注了@Bean注解的方法逻辑去创建Bean,并注入到容器中。
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package org.springframework.context.annotation; 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.beans.factory.annotation.Autowire; import org.springframework.core.annotation.AliasFor; @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Bean {
//指定Bean的名称,当没有指定时,默认使用被标注的方法名作为Bean的名称
//AliasFor表示与name互为别名,效果一样,指定其一即可 @AliasFor("name") String[] value() default {};
//与value属性一样 @AliasFor("value") String[] name() default {};
//用的不多,不去了解 Autowire autowire() default Autowire.NO;
//指定Bean的初始化方法,为Bean中的某个方法名,不受修饰符的干扰,在Bean实例化后调用 String initMethod() default "";
//指定Bean的自动销毁方法,在Bean的生命周期结束时,会自动调用该方法,同样不受修饰符的限制 String destroyMethod() default "(inferred)"; }