Bean的创建
配置Spring自动扫描组件
- XML的配置方式
@Component
public class OneBean {
}
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
OneBean bean = context.getBean("oneBean",OneBean.class);
System.out.println(bean);
}
- Java Config
@Configuration //标注了该注解的类是一个Spring的配置类,等价于原先的applicationContext.xml
@ComponentScan // 启动该注解,表明, 开启Spring的注解自动扫描 , 默认情况下,扫描当前类所在包及其子包
public class Config {
}
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
OneBean oneBean = context.getBean(OneBean.class);
System.out.println(oneBean);
}
构造器创建bean
- XML
- Java Config
@Configuration
public class Config {
@Bean // 表明这是一个Spring 管理的bean
public OneBean oneBean() {
// 显然,这个Bean的CLass 是OneBean.class
// 在spring 中,bean的 id 是不能重复的,而现在使用java config来代替xml配置
// 在java config 方法名就是这个bean的id
return new OneBean();
}
}
静态工厂方法创建bean
示例代码:
public class OneBean {
}
public class OneBeanFactory {
public static OneBean getOneBean() {
return new OneBean();
}
}
- XML
- Java Config
@Configuration
public class Config {
@Bean
public OneBean oneBean1() {
return OneBeanFactory.getOneBean();
}
}
实例工厂方法创建bean
代码示例:
public class OneBean {
}
public class OneBeanFactory {
public OneBean getOneBean() {
return new OneBean();
}
- XML
- Java Config
@Configuration
public class Config {
@Bean
public OneBean oneBean2() {
return new OneBeanFactory().getOneBean();
}
}
通过FactoryBean创建Bean
代码示例:
public class OneBean {
}
public class OneBeanFactory implements FactoryBean {
@Override
public OneBean getObject() throws Exception {
return new OneBean();
}
@Override
public Class> getObjectType() {
return OneBean.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
- XML
- Java Config
@Configuration
public class Config {
/**
* OneBeanFactory 类实现了 Spring的 FactoryBean 接口,
* Spring 知道这个类是用来创建 OneBean 对象的,
* 方法虽然返回了 OneBeanFactory , 但是Spring 会帮我们用这个类来创建 OneBean
*/
@Bean
public OneBeanFactory oneBean() {
return new OneBeanFactory();
}
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
OneBean oneBean = context.getBean("oneBean", OneBean.class);
System.out.println(oneBean);
// 通过 "&"的方式获取对应的Factory
OneBeanFactory oneBeanFactory = context.getBean("&oneBean", OneBeanFactory.class);
System.out.println(oneBeanFactory);
}
}
可以通过"&"的方式来获取对应Factory的原因
public interface BeanFactory {
/**
* Used to dereference a {@link FactoryBean} instance and distinguish it from
* beans created by the FactoryBean. For example, if the bean named
* {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
* will return the factory, not the instance returned by the factory.
*/
String FACTORY_BEAN_PREFIX = "&";
修改Bean的Scope
Scope选项:
-
singleton
: 单例。默认情况下,Spring中的Bean都是单例的。 -
prototype
: 多例。表示每次获得Bean都会生成一个新的对象。注意:scope为prototype的Bean,在Spring容器启动的时候不会初始化这些Bean -
request
: 表示在一次http请求中创建Bean(只适用于web应用) -
session
: 表示在一个用户会话内(HttpSession)有效(只适用于web应用)
配置
- XML
- Java Config
@Configuration
public class Config {
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public OneBean oneBean() {
return new OneBean();
}
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
OneBean oneBean1 = context.getBean("oneBean", OneBean.class);
OneBean oneBean2 = context.getBean("oneBean", OneBean.class);
System.out.println(oneBean1 == oneBean2); //false
}
}
Bean的注入
普通元素的注入
需求代码:
@Setter
@ToString
public class OneBean {
private String name;
}
- XML
- Java Config
@Configuration
public class Config {
@Bean
public OneBean oneBean() {
OneBean oneBean = new OneBean();
oneBean.setName("xxx");
return oneBean;
}
}
Java Config 实现对象注入
示例代码:
@Setter
@Getter
public class SomeBean {
private OtherBean otherBean;
}
public class OtherBean {
}
@Configuration
public class Config {
@Bean
public OtherBean otherBean() {
return new OtherBean();
}
@Bean
public OtherBean otherBean2() {
return new OtherBean();
}
@Bean
public SomeBean someBean() {
SomeBean someBean = new SomeBean();
//因为在otherBean()方法上有@Bean注解
//Spring会拦截所有对该方法的调用.并确保直接返回该方法创建的Bean
someBean.setOtherBean(otherBean());
return someBean;
}
/**
* 也可以通过方法的参数来注入所需要的对象
* 通过这种方式来引用其他的Bean通常是最佳的选择.
* 因为他不会要求被注入的Bean和当前Bean声明到同一个配置类中
*
* 如果Spring的容器中存在 相同类型 的Bean ,
* 1> 可以使用 @Qualifier("name") 来指定Bean的name
* 2> 也可以使用 方法参数名 来 指定对应的Bean
*/
// @Bean
// public SomeBean someBean2(@Qualifier("otherBean2") OtherBean bean) {
// SomeBean someBean = new SomeBean();
// someBean.setOtherBean(bean);
// return someBean;
// }
@Bean
public SomeBean someBean2(OtherBean otherBean) {
SomeBean someBean = new SomeBean();
someBean.setOtherBean(otherBean);
return someBean;
}
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
SomeBean someBean = context.getBean("someBean2", SomeBean.class);
OtherBean otherBean = context.getBean("otherBean", OtherBean.class);
OtherBean otherBean2 = context.getBean("otherBean2", OtherBean.class);
System.out.println(someBean.getOtherBean() == otherBean); //true
System.out.println(someBean.getOtherBean() == otherBean2); //false
}
}
使用Java Config @Bean 注解的方式可以采用任何必要的Java 功能来构建Bean。
@Autowired 和 @Resource
@Autowired
- spring提供的注解.作用于字段或者setter方法,根据依赖对象类型去找.
- 默认情况下必须要求依赖对象必须存在;如果要允许null 值,可以设置它的required属性为false
@Autowired(required=false)
- 可以通过使用
@Qualifier
来指定bean的name
@Resource
- J2EE规范的注解,
@Resource
也可以作用于字段或者setter方法 -
@Resource
必须要求有匹配的对象 - 首先按照名字去找;如果按照名字找不到,再按照类型去找,但如果找到多个匹配类型,报错
- 可以直接使用name属性指定bean的名称
@Resource(name="mybean1")
private Mybean mybean;
等价于
@Autowired
@Qualifier("mybean1")
private Mybean mybean;
Bean的初始化和销毁方法
需求:
- 某些bean需要在spring实例化完成之后,去调用bean上面的一个初始化方法来完成bean的初始化工作。
- 某些bean需要在spring正常销毁之前,调用一个结束方法(销毁方法)去完成一些清理工作。
示例代码:
public class OneBean {
public void init() {
System.out.println("init...");
}
public void close() {
System.out.println("close...");
}
}
- XML
- Java Config
@Configuration
public class Config {
@Bean(initMethod = "init", destroyMethod = "close")
public OneBean oneBean() {
return new OneBean();
}
public static void main(String[] args) {
//ClassPathXmlApplicationContext 和 AnnotationConfigApplicationContext 都 实现了 AutoCloseable 接口
// 只有正常关闭Spring容器,才会调用Bean 的destroyMethod
try (AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(Config.class)) {
OneBean oneBean = context.getBean("oneBean", OneBean.class);
}
}
}
- 实现Spring的 InitializingBean 和 DisposableBean 接口
@Component
public class SomeBean implements InitializingBean, DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("close...");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("inti..");
}
}
- 使用J2EE规范注解 @PostConstruct 和 @PreDestroy
@Component
public class OtherBean {
@PostConstruct
public void close() throws Exception {
System.out.println("close...");
}
@PreDestroy
public void init() throws Exception {
System.out.println("inti..");
}
}
注意:
- 如果手动启动容器,必须要正常关闭spring容器,才能调用到destory-method。
- 如果bean的scope是prototype,spring不会调用destory-method。