通过注解设定Bean的作用域
1、Spring预定义作用域
xml形式
<bean id="bean" class="com.demo.ioc.Person" scope="singleton"/>
注解形式
@Component @Scope("singleton") // prototype public class Person { } // 或者 @Configuration @ComponentScan(value = "com.demo.ioc") public class MyConfiguration { @Bean @Scope("singleton") public Person person() { return new Person(); }
2、自定义Scope作用域
回忆之前的自定义Scope代码
package com.demo.ioc; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.config.Scope; import java.util.Map; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; /** * 自定义作用域 * 实现双例模式(每一个Bean对应两个实例) */ public class MyScope implements Scope { Map<String, Object> map1 = new ConcurrentHashMap<>(); Map<String, Object> map2 = new ConcurrentHashMap<>(); @Override public Object get(String name, ObjectFactory<?> objectFactory) { //先从map1取 if (!map1.containsKey(name)) { Object obj = objectFactory.getObject(); map1.put(name, obj); return obj; } //再从map2取 if (!map2.containsKey(name)) { Object obj = objectFactory.getObject(); map2.put(name, obj); return obj; } // 如果map1和map2中都存在则随机返回 int i = new Random().nextInt(2); if (i == 0) { return map1.get(name); } else { return map2.get(name); } } @Override public Object remove(String name) { // 和添加顺序正好相反 if(map2.containsKey(name)){ Object obj = map2.get(name); map2.remove(name); return obj; } if(map1.containsKey(name)){ Object obj = map1.get(name); map1.remove(name); return obj; } return null; } @Override public void registerDestructionCallback(String name, Runnable callback) { } @Override public Object resolveContextualObject(String key) { return null; } @Override public String getConversationId() { return null; } }
xml形式
<!-- 1、将Scope交由Spring管理 --> <bean id="myScope" class="com.demo.ioc.MyScope"/> <!-- 2、配置 --> <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="myScope" value-ref="myScope"/> </map> </property> </bean> <!-- 3、使用 --> <bean class="com.demo.ioc.Bean" id="bean" scope="myScope"/>
注解形式
package com.demo.ioc; import org.springframework.beans.factory.config.CustomScopeConfigurer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; // 创建配置文件,可以认为是一个xml配置文件 @Configuration @ComponentScan(value = "com.demo.ioc") public class MyConfiguration { // 1、交由Spring管理 @Bean public MyScope myScope(){ return new MyScope(); } // 2、配置 @Bean public CustomScopeConfigurer customScopeConfigurer(){ CustomScopeConfigurer configurer = new CustomScopeConfigurer(); configurer.addScope("myScope", myScope()); return configurer; } // 3、使用 @Bean @Scope("myScope") public Person person() { return new Person(); } }
测试
package com.demo.ioc; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class BeanTest { @Test public void testBean() { // 获取上下文 ApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class); // 获取Bean for (int i = 0; i < 10; i++) { Person bean = context.getBean("person", Person.class); System.out.println(bean); } } }
Bean注解的方式进行方法注入
回顾方法注入场景:
Bean1是singleton, Bean2是prototype, Bean1依赖于Bean2
我们希望每次调用Bean1某个方法时候,该方法每次拿到Bean2都是新的实例
package com.demo.ioc; public class Bean2 { } package com.demo.ioc; public abstract class Bean1 { protected abstract Bean2 createBean2(); }
xml方式
<bean id="bean2" class="com.demo.ioc.Bean2" scope="prototype"/>
<bean id="bean1" class="com.demo.ioc.Bean1" scope="singleton">
<lookup-method name="createBean2" bean="bean2"/>
</bean>
注解形式
package com.demo.ioc; @Component @Scope("prototype") public class Bean2 { } package com.demo.ioc; @Component public abstract class Bean1 { @Lookup protected abstract Bean2 createBean2(); }
通过注解开启Bean的懒加载
xml形式
<!-- 单个 --> <bean class="com.demo.ioc.Bean" id="bean" lazy-init="true"/> <!-- 全局 --> <beans default-lazy-init="true"></beans>
注解形式
/** * 单个 */ @Configuration @ComponentScan(value = "com.demo.ioc") public class MyConfiguration { @Bean @Lazy public Person person() { return new Person(); } } // 或者 @Component @Lazy public class Person { } /** * 全局 */ @Configuration @ComponentScan(value = "com.demo.ioc") @Lazy public class MyConfiguration { @Bean public Person person() { return new Person(); } }
通过注解编写Bean初始化及销毁
配置文件
package com.demo.ioc; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; // 创建配置文件,可以认为是一个xml配置文件 @Configuration @ComponentScan(value = "com.demo.ioc") public class MyConfiguration { }
上下文测试
package com.demo.ioc; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.AbstractApplicationContext; public class BeanTest { @Test public void testBean() { // 获取上下文 AbstractApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class); Person bean = context.getBean("person", Person.class); context.close(); } }
方式一:
package com.demo.ioc; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.stereotype.Component; @Component public class Person implements InitializingBean, DisposableBean { @Override public void destroy() throws Exception { System.out.println("Person.destroy"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("Person.afterPropertiesSet"); } }
方式二:
package com.demo.ioc; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @Component public class Person { @PostConstruct public void onInit(){ System.out.println("Person.onInit"); } @PreDestroy public void onDestroy(){ System.out.println("Person.onDestroy"); } }
方式三
package com.demo.ioc; public class Person { public void onInit() { System.out.println("Person.onInit"); } public void onDestroy() { System.out.println("Person.onDestroy"); } }
通过Bean设置参数
package com.demo.ioc; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan(value = "com.demo.ioc") public class MyConfiguration { @Bean(initMethod = "onInit", destroyMethod = "onDestroy") public Person person() { return new Person(); } }