Spring
Java Web发展历史- 第一阶段 JavaBean + Servlet + JSP
- 第二阶段 EJB重量级框架
- 第三阶段 SpringMVC/Struts + Spring + Hibernate/MyBatis
- 第四阶段 SpringBoot 约定大于配置
- 第五阶段 Dubbo为代表的SOA微服务架构体系
- 第六阶段 SpringCloud 微服务框架爱技术生态圈
- 介绍IoC并编写一个简单的IoC容器
- 介绍通过xml方式完成SpringIoC对Bean的管理
- 介绍SpringIoC相关注解的使用
IoC Inversion of Control 控制反转,依赖注入
控制:控制对象的创建及销毁(生命周期) 反转:将对象的控制权交给IoC容器
简化约定
- 所有的Bean的生命周期都交由IoC容器管理
- 所有被依赖的Bean通过构造函数方法执行注入
- 被依赖的Bean需要优先创建
依赖关系
Car
+start()
+stop()
+turnLeft()
+turnRight()
测试
package com.demo.ioc;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanTest {
@Test
public void testBean(){
// 获取上下文
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
// 获取bean
Bean bean = context.getBean("bean", Bean.class);
System.out.println(bean);
}
}
实例化Bean方式
- 通过构造方法实例化Bean
- 通过静态方法实例化Bean
- 通过实例方法实例化Bean
- Bean的别名
1、通过构造方法实例化Bean
package com.demo.ioc;
public class Bean {
public Bean(){}
}
2、通过静态方法实例化Bean
package com.demo.ioc;
public class BeanFactory {
public static Bean createBean(){
return new Bean();
}
}
3、通过实例方法实例化Bean
package com.demo.ioc;
public class BeanFactory {
public Bean createBean(){
return new Bean();
}
}
4、Bean的别名
注入Bean方式
通过构造方法注入Bean 通过set方式注入Bean 集合类Bean的注入(List、Set、Map、Properties) null注入 注入时创建内部Bean
1、通过构造方法注入Bean
package com.demo.ioc;
public class Bean {
private String name;
private AnotherBean anotherBean;
public Bean(String name, AnotherBean anotherBean) {
this.name = name;
this.anotherBean = anotherBean;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public AnotherBean getAnotherBean() {
return anotherBean;
}
public void setAnotherBean(AnotherBean anotherBean) {
this.anotherBean = anotherBean;
}
@Override
public String toString() {
return "Bean{" +
"name='" + name + '\'' +
", anotherBean=" + anotherBean +
'}';
}
}
package com.demo.ioc;
public class AnotherBean {
}
简化写法
2、通过set方式注入Bean
package com.demo.ioc;
public class Bean {
private String name;
private AnotherBean anotherBean;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public AnotherBean getAnotherBean() {
return anotherBean;
}
public void setAnotherBean(AnotherBean anotherBean) {
this.anotherBean = anotherBean;
}
@Override
public String toString() {
return "Bean{" +
"name='" + name + '\'' +
", anotherBean=" + anotherBean +
'}';
}
}
简化写法
3、集合类Bean的注入(List、Set、Map、Properties)
package com.demo.ioc;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class Bean {
private List stringList;
private List anotherBeanList;
private Set stringSet;
private Set anotherBeanSet;
private Map stringMap;
private Map anotherBeanMap;
private Properties properties;
private AnotherBean anotherBean1;
private AnotherBean anotherBean2;
public void setAnotherBean1(AnotherBean anotherBean1) {
this.anotherBean1 = anotherBean1;
}
public void setAnotherBean2(AnotherBean anotherBean2) {
this.anotherBean2 = anotherBean2;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
public void setStringList(List stringList) {
this.stringList = stringList;
}
public void setAnotherBeanList(List anotherBeanList) {
this.anotherBeanList = anotherBeanList;
}
public void setStringSet(Set stringSet) {
this.stringSet = stringSet;
}
public void setAnotherBeanSet(Set anotherBeanSet) {
this.anotherBeanSet = anotherBeanSet;
}
public void setStringMap(Map stringMap) {
this.stringMap = stringMap;
}
public void setAnotherBeanMap(Map anotherBeanMap) {
this.anotherBeanMap = anotherBeanMap;
}
}
Tom
Jack
Tom
Jack
Tom
Bean作用域
- singleton作用域(单例,限定在一个上下文环境中)
- prototype作用域(多例)
- Web环境作用域
- request作用域
- session作用域
- application作用域
- websocket作用域
- 自定义作用域
- SimpleThreadScope作用域
总结
配置
-Bean1-singletonBean1-prototypeBean2-singletonbean1单实例、bean2单实例bean1多实例、bean2单实例Bean2-prototypebean1单实例、bean2单实例bean1多实例、bean2多实例
方法注入
场景: 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();
}
Web环境作用域
项目结构
$ tree
.
├── pom.xml
└── src
└── main
├── java
│ └── com
│ └── demo
│ ├── ApplicationController.java
│ ├── RequestController.java
│ └── SessionController.java
├── resources
│ └── spring.xml
└── webapp
└── WEB-INF
└── web.xml
pom.xml
4.0.0
spring-mvc
com.demo
1.0-SNAPSHOT
war
org.springframework
spring-core
5.1.3.RELEASE
org.springframework
spring-context
5.1.3.RELEASE
org.springframework
spring-web
5.1.3.RELEASE
org.springframework
spring-webmvc
5.1.3.RELEASE
web.xml
SpringServlet
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:spring.xml
SpringServlet
/*
RequestController.java
package com.demo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class RequestController {
@RequestMapping("/request")
@ResponseBody
public String test(){
return this.toString();
}
}
SessionController.java
package com.demo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class SessionController {
@RequestMapping("/session")
@ResponseBody
public String test(){
return this.toString();
}
}
ApplicationController.java
package com.demo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class ApplicationController {
@RequestMapping("/application")
@ResponseBody
public String test(){
return this.toString();
}
}
总结
reuqest:每个request请求都会创建一个单独的实例。
session:每个session都会创建一个单独的实例。
application:每个sercletContext都会创建一个单独的实例。
websocket:每个websocket链接都会创建一个单独的实例。
自定义作用域双例模式
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 map1 = new ConcurrentHashMap();
Map 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;
}
}
package com.demo.ioc;
public class Bean {
}
测试
package com.demo.ioc;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanTest {
@Test
public void testBean(){
// 获取上下文
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
for (int i = 0; i
package com.demo.ioc;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanTest {
@Test
public void testBean(){
// 获取上下文
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
for (int i = 0; i
为所有Bean设定为懒加载
适用场景
如果某个Bean在程序整个运行周期都可能不会被使用,那么可考虑设定该Bean为懒加载。
优点:尽可能的节省了资源。
缺点:可能会导致某个操作响应时间增加。
Bean的初始化及销毁逻辑处理1、如果需要在Bean实例化之后执行一些逻辑,有两种方法:
-
使用init-method属性
-
让Bean实现InitializingBean接口
2、如果需要在Bean销毁之前执行一些逻辑,有两种方法:
-
使用destory-method属性
-
让Bean实现DisposableBean接口
3、通过指定方法名实现
package com.demo.ioc;
public class Bean {
public void onInit(){
System.out.println("onInit");
}
public void onDestroy(){
System.out.println("onDestroy");
}
}
单个Bean初始化和销毁方法执行
所有Bean初始化和销毁方法执行
package com.demo.ioc;
import org.junit.Test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanTest {
@Test
public void testBean(){
// 获取上下文
AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
// 关闭上下文
context.close();
}
}
4、通过实现接口
package com.demo.ioc;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class Bean implements InitializingBean, DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("destroy");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet");
}
}
Bean属性继承
package com.demo.ioc;
public class Parent {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.demo.ioc;
public class Child1 extends Parent{
private String name1;
public String getName1() {
return name1;
}
public void setName1(String name1) {
this.name1 = name1;
}
@Override
public String toString() {
return "Child1{" +
"name='" + getName() + '\'' +
"name1='" + name1 + '\'' +
'}';
}
}
package com.demo.ioc;
public class Child2 extends Parent{
private String name2;
public String getName2() {
return name2;
}
public void setName2(String name2) {
this.name2 = name2;
}
@Override
public String toString() {
return "Child1{" +
"name='" + getName() + '\'' +
"name2='" + name2 + '\'' +
'}';
}
}
继承关系配置
或者非继承关系,有相同的属性
SpringIoC注解的基本使用
pom.xml依赖
org.springframework
spring-core
5.1.3.RELEASE
org.springframework
spring-context
5.1.3.RELEASE
junit
junit
4.13
test
1、使用xml文件
package com.demo.ioc;
public class Bean{
}
创建spring.xml配置文件
获取Bean
package com.demo.ioc;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanTest {
@Test
public void testBean() {
// 获取上下文
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
// 获取Bean
Bean bean = context.getBean("bean", Bean.class);
System.out.println(bean);
}
}
2、使用annotation
package com.demo.ioc;
public class Person {
}
package com.demo.ioc.human;
import com.demo.ioc.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// 创建配置文件
@Configuration
public class MyConfiguration {
// 将Bean交由Spring创建并管理
// name参数可以省略,默认方法名就是bean的名称
@Bean(name = "person")
public Person person(){
return new Person();
}
}
获取Bean
package com.demo.ioc;
import com.demo.ioc.human.MyConfiguration;
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
Person bean = context.getBean("person", Person.class);
System.out.println(bean);
}
}
包扫描
1、xml方式
2、注解方式
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.springframework.stereotype.Component;
// 增加注解后会被Spring扫描到, 默认的Id是类名首字母小写
@Component(value = "person")
public class Person {
}
注解
@Component // 通用型注解
@Controller // Controller层
@Service // Service层
@Repository // Dao层
Bean别名
xml形式
注解方式
package com.demo.ioc;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// 创建配置文件,可以认为是一个xml配置文件
@Configuration
public class MyConfiguration {
@Bean(name = {"person1", "person2"})
public Person person(){
return new Person();
}
}
通过注解注入Bean
- 通过方法注入Bean
- 通过构造方法注入Bean
- 通过Set方法注入Bean
- 通过属性注入Bean
- 集合类Bean类型注入
- 直接注入集合实例
- 将多个泛型的实例注入到集合
- 将多个泛型实例注入到List
- 控制泛型示实例在List中的顺序
- 将多个泛型的实例注入到Map
- String、Integer等类型直接赋值
- SpringIoC容器内置接口示例注入
准备Bean
package com.demo.ioc;
import org.springframework.stereotype.Component;
@Component
public class Cat {
}
package com.demo.ioc;
import org.springframework.stereotype.Component;
@Component
public class Dog {
}
package com.demo.ioc;
import org.springframework.stereotype.Component;
@Component
public class Pig {
}
配置文件
package com.demo.ioc;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
// 创建配置文件,可以认为是一个xml配置文件
@Configuration
@ComponentScan(value = "com.demo.ioc")
public class MyConfiguration {
@Bean(name = "stringList")
public List stringList() {
List list = new ArrayList();
list.add("Tom");
list.add("Jack");
return list;
}
// 此优先级高于 List
@Bean
@Order(2) // 指定优先级
public String string1(){
return "string1";
}
@Bean
@Order(1)
public String string2(){
return "string2";
}
@Bean
public Map stringIntegerMap(){
Map map = new HashMap();
map.put("dog", 23);
map.put("pig", 24);
return map;
}
// 优先级高于 Map
@Bean
public Integer integer1(){
return 222;
}
@Bean
public Integer integer2(){
return 223;
}
}
注入实例
package com.demo.ioc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
@Component
public class Person {
private Dog dog;
// 1、构造方法注入
@Autowired
public Person(Dog dog) {
this.dog = dog;
}
private Cat cat;
// 2、Set方法注入
@Autowired
public void setCat(Cat cat) {
this.cat = cat;
}
// 3、通过属性注入
@Autowired
private Pig pig;
private List stringList;
// 4、注入List类型
@Autowired
// 指定Bean的ID
// @Qualifier(value = "stringList")
public void setStringList(List stringList) {
this.stringList = stringList;
}
public List getStringList() {
return stringList;
}
// 5、Map类型注入
private Map stringIntegerMap;
public Map getStringIntegerMap() {
return stringIntegerMap;
}
@Autowired
public void setStringIntegerMap(Map stringIntegerMap) {
this.stringIntegerMap = stringIntegerMap;
}
private String name;
// 6、String、Integer等类型直接赋值
@Value("Tom") // 如果是Integer会自动转型
public void setName(String name) {
this.name = name;
}
// 7、容器内置接口注入
private ApplicationContext context;
@Autowired
public void setContext(ApplicationContext context) {
this.context = context;
}
public ApplicationContext getContext() {
return context;
}
@Override
public String toString() {
return "Person{" +
"dog=" + dog +
", cat=" + cat +
", pig=" + pig +
", stringList=" + stringList +
", stringIntegerMap=" + stringIntegerMap +
", name='" + name + '\'' +
'}';
}
}
测试
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
Person bean = context.getBean("person", Person.class);
System.out.println(bean);
System.out.println(bean.getStringList());
System.out.println(bean.getStringIntegerMap());
System.out.println(bean.getContext().getBean("cat"));
}
}
测试输出
Person{dog=com.demo.ioc.Dog@441772e,
cat=com.demo.ioc.Cat@7334aada,
pig=com.demo.ioc.Pig@1d9b7cce,
stringList=[string2, string1],
stringIntegerMap={integer1=222, integer2=223},
name='Tom'
}
[string2, string1]
{integer1=222, integer2=223}
com.demo.ioc.Cat@7334aada
通过注解设定Bean的作用域
1、Spring预定义作用域
xml形式
注解形式
@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 map1 = new ConcurrentHashMap();
Map 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形式
注解形式
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
注解形式
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形式
注解形式
/**
* 单个
*/
@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();
}
}