几种定义Bean的方式(声明式)
-
Bean标签取生成一个Bean
在java中
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); //通过xml文件所指定的类的构造方法获取bean
在spring.xml文件中
<bean id="user" class="com.datum.User"/>
-
@Component
给某个类上加上@Component,再在配置类Config.java上写@ComponentScan(“包地址”)或者在spring.xml中写入一个标签<context:component-scan base-package=“com.datum”/>
在将配置类传入Context,同样能通过getBean方法拿到对象
-
@Bean
方法名字为容器获取bean的名“user”
性能要比xml要高点(解析xml文件过程)
@Bean方式要简洁灵活点
public class Config { @Bean public User user() {//方法名字为容器获取bean的名“user” return new User(); } }
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(); annotationConfigApplicationContext.register(Config.class); annotationConfigApplicationContext.refresh(); User user1 = annotationConfigApplicationContext.getBean("user", User.class);
通过AnnotationConfigApplicationContext来获取一个写上注解的Bean
JavaBean SpringBean 对象之间的区别
Bean肯定是对象。
JavaBean 成员是私有的,但是要提供针对该成员的get,set方法
SpringBean 凡是由Spring生产管理的Bean都叫SpringBean
BeanDefinition(编程式定义bean,是声明式的核心)
编程式定义一个Bean
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(User.class);
annotationConfigApplicationContext.registerBeanDefinition("user", beanDefinition);
annotationConfigApplicationContext.refresh();
User user = annotationConfigApplicationContext.getBean("user", User.class);
System.out.println(user);
首先获取一个context,然后通过beanDefinition设置一个BeanClass,并且注册道context,同样可以获得一个bean
FactoryBean
继承FactoryBean接口
public class DatumFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
return new Person();
}
@Override
public Class<?> getObjectType() {
return Person.class;
}
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
可以通过BeanDefinition来注册一个bean
AbstractBeanDefinition beanDefinition1 = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition1.setBeanClass(DatumFactoryBean.class);
annotationConfigApplicationContext.registerBeanDefinition("datum", beanDefinition1);
Person datum = annotationConfigApplicationContext.getBean("datum", Person.class);
DatumFactoryBean bean = annotationConfigApplicationContext.getBean("&datum", DatumFactoryBean.class);
System.out.println(datum);
System.out.println(bean);
注意 一个FactoryBean注册会将会产生两个Bean,一个是FactoryBean本身,一个是实现FactoryBean的getObject方法的返回对象。
"datum"对应Person.class "&datum"对应DatumFactoryBean.class
如何注册一个Bean
通过@Component注册bean则需要一个@ComponentScan的class或者xml配置
通过registerBean只需要类就可以了
通过书写xml标签
通过在类上加上@component标签,在通过一个配置类Config加上@ComponentScan(“包地址”),再去context中调用context.register(Config.class)。
通过直接调用context.registerBean(User.class)方法直接注册一个Bean,后续再调用,默认调用名为首字母小写即"user"。
通过context.registerBean()传入一个Supplier
context.registerBean(User.class, new Supplier<User>() {
@Override
public User get() {
User user = new User();
user.setName("hello");
return user;
}
});
User user = context.getBean("user", User.class);
System.out.println(user.getName());
这个方法也可以注册一个bean
Spring容器到底是什么
<bean id="user" class="com.datum.User"/>
<bean id="user1" class="com.datum.User" scope="prototype"/>
scope::prototype原型
scope::singleton单例(spring默认是单例)
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
System.out.println(context.getBean("user", User.class));
System.out.println(context.getBean("user", User.class));
System.out.println(context.getBean("user1", User.class));
System.out.println(context.getBean("user1", User.class));
com.datum.User@51b279c9
com.datum.User@51b279c9
com.datum.User@1ad282e0
com.datum.User@7f416310
"user"打印的地址是一致的
"user1"打印的地址是不同的,对象就不同
单例池
spring启动的时候回去把非懒加载的单例池创建出来
ConcurrentHashMap singletonObject
key为String(BeanName),value为Object
BeanFactory Bean工厂
生产bean,在getBean()的时候容器中的Bean被创建(无论是不是singleton)。
是一个容器
主要储存 BeanDefinition和对象
有单例池,DefaultListableBeanFactory继承自DefaultSingletonBeanRegistry,该类有private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256)成员
但是不止是存储单例,可以通过beanDefinition设置scope为prototype(原型)
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerSingleton("user", new User());
User user = beanFactory.getBean("user", User.class);
System.out.println(user);
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(User.class);
beanFactory.registerBeanDefinition("user1", beanDefinition);
User user1 = beanFactory.getBean("user1", User.class);
System.out.println(user1);
ApplicationContext
ApplicationContext容器里面的scope为singleton的对象在spring启动的时候创建,scope为prototype的对象在获取的时候创建。
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver
继承了很多接口,集成了很多功能,例如EnvironmentCapable获取系统和jvm环境,MessageSource国际化,ApplicationEventPublisher事件发布,ResourcePatternResolver资源匹配,资源解析
拥有BeanFactory的功能并且超越了BeanFactory
通过context获取系统环境,和jvm环境
AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext();
System.out.println(applicationContext.getEnvironment().getSystemEnvironment()); System.out.println(applicationContext.getEnvironment().getSystemProperties());
ClassPathXmlApplicationContext和FileSystemXmlApplicationContext的区别
ClassPathXmlApplicationContext(“spring.xml”)代码中的spring.xml指的是classpath:目录下的spring.xml
FileSystemXmlApplicationContext(“spring.xml”)代码中的spring.xml指的是工程目录下的spring.xml
FileSystemXmlApplicationContext(“src/main/resources/spring.xml”)等同classpath:目录下的spring.xml
ClassPathXmlApplicationContext:不指绝对路径,只支持从classpath相对路径
FileSystemXmlApplicationContext:支持绝对路径,也支持工程目录相对路径
ClassPathXmlApplicationContext和AnnotationConfigApplication的区别
ClassPathXmlApplicationContext:通过传入一个xml文件,支持重复刷新,因为它继承了AbstractRefreshableConfigApplicationContext–》AbstractRefreshableApplicationContext
AnnotationConfigApplication:通过传入一个配置类的.class,不支持重复刷新,它继承自GenericApplicationContext
刷新后的效果相当与把所有bean对象销毁,重新读取spring.xml文件再重新生成bean
所有单例bean不再是之前的bean