Spring IOC容器之Bean管理 1 基于xml方式
在Spring配置文件中,在bean标签里面添加对应的属性,就可以实现对象的创建。
1.1 创建对象
1 2 3 4 5 6 7 8 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:p ="http://www.springframework.org/schema/p" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" > <bean id ="user" class ="com.company.User" > </bean > </beans >
1 2 3 4 5 6 7 public class Test { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml" ); User user = context.getBean("user" , User.class); System.out.println(user); } }
1.2 注入属性 1.2.1 set方法
1 2 3 4 5 6 7 public void setName (String name) { this .name = name; } public void setAddress (String address) { this .address = address; }
配置文件中在bean标签下使用property标签设置属性,
1 2 3 4 5 6 7 8 9 10 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" > <bean id ="user" class ="com.company.User" > <property name ="name" value ="Xiaohua" > </property > <property name ="address" value ="Shanghai" > </property > </bean > </beans >
1 2 3 4 5 6 7 8 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:p ="http://www.springframework.org/schema/p" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" > <bean id ="user" class ="com.company.User" p:name ="Xiaohua" p:address ="Shanghai" > </bean > </beans >
1 2 3 <property name ="telephone" > <null > </null > </property >
1 2 3 <property name ="favoriteBook" > <value > <![CDATA[《你好,明天!》]]></value > </property >
1.2.2 有参构造函数
1 2 3 4 public User (String name, String address) { this .name = name; this .address = address; }
配置文件中在bean标签下使用constructor-arg标签初始化对象,
1 2 3 4 5 6 7 8 9 10 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" > <bean id ="user" class ="com.company.User" > <constructor-arg name ="name" value ="Lihua" > </constructor-arg > <constructor-arg name ="address" value ="Beijing" > </constructor-arg > </bean > </beans >
1.2.3 外部bean
1 2 3 4 5 6 7 8 9 10 11 12 public class UserService { private UserDao userDao; public void setUserDao (UserDao userDao) { this .userDao = userDao; } public void update () { System.out.println("UserService update......" ); userDao.update(); } }
例如上面的代码,UserService类中就包含了一个UserDao对象
如果需要初始化类内的对象属性,可以使用ref以外部bean的形式配置,
1 2 3 4 <bean id ="userDao" class ="com.company.dao.UserDaoImpl" > </bean > <bean id ="userService" class ="com.company.service.UserService" > <property name ="userDao" ref ="userDao" > </property > </bean >
1.2.4 内部bean
也可以在property标签内部初始化对象属性,这种方式被称为内部bean,
1 2 3 4 5 <bean id ="userService" class ="com.company.service.UserService" > <property name ="userDao" > <bean id ="userDao" class ="com.company.dao.UserDaoImpl" > </bean > </property > </bean >
1.2.5 级联赋值 1 2 3 4 5 6 <bean id ="userService" class ="com.company.service.UserService" > <property name ="userDao" > <bean id ="userDao" class ="com.company.dao.UserDaoImpl" > </bean > </property > <property name ="userDao.name" value ="Lihua" > </property > </bean >
需要提前定义好get和set方法,否则会报错
先在UserService对象中创建UserDao对象,然后调用get方法获得UserDao对象,最后调用setName方法为name属性赋值
1.2.6 集合属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class Student { private String[] courses; private List<String> nicknames; private Map<String, String> contactMethod; private Set<String> friends; public void setCourses (String[] courses) { this .courses = courses; } public void setNicknames (List<String> nicknames) { this .nicknames = nicknames; } public void setContactMethod (Map<String, String> contactMethod) { this .contactMethod = contactMethod; } public void setFriends (Set<String> friends) { this .friends = friends; } public void show () { System.out.println(Arrays.toString(courses)); System.out.println(nicknames); System.out.println(contactMethod); System.out.println(friends); } }
1.2.6.1 数组 1 2 3 4 5 6 7 <property name ="courses" > <array > <value > Java程序设计</value > <value > 汇编语言</value > <value > 操作系统原理</value > </array > </property >
1.2.6.2 List集合 1 2 3 4 5 6 <property name ="nicknames" > <list > <value > Xiaoming</value > <value > Mingming</value > </list > </property >
1.2.6.3 Map集合 1 2 3 4 5 6 <property name ="contactMethod" > <map > <entry key ="tele" value ="123xxxxxxxx" > </entry > <entry key ="qq" value ="234xxxxx" > </entry > </map > </property >
1.2.6.4 Set集合 1 2 3 4 5 6 <property name ="friends" > <set > <value > Lihua</value > <value > Xiaohong</value > </set > </property >
1.2.6.5 在集合里面设置对象类型值
1 2 3 4 5 6 7 8 9 10 11 public class BookShelf { private List<Book> books; public void setBooks (List<Book> books) { this .books = books; } public void show () { System.out.println(books); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <bean id ="book1" class ="com.company.Book" > <property name ="name" value ="面向对象程序设计" > </property > </bean > <bean id ="book2" class ="com.company.Book" > <property name ="name" value ="数据库原理" > </property > </bean > <bean id ="bookShelf" class ="com.company.BookShelf" > <property name ="books" > <list > <ref bean ="book1" > </ref > <ref bean ="book2" > </ref > </list > </property > </bean >
1.2.6.6 把集合注入部分提取出来
1 2 3 4 5 <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:util ="http://www.springframework.org/schema/util" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd" >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <bean id ="book1" class ="com.company.Book" > <property name ="name" value ="面向对象程序设计" > </property > </bean > <bean id ="book2" class ="com.company.Book" > <property name ="name" value ="数据库原理" > </property > </bean > <bean id ="book3" class ="com.company.Book" > <property name ="name" value ="计算机网络" > </property > </bean > <util:list id ="books" > <ref bean ="book1" > </ref > <ref bean ="book2" > </ref > <ref bean ="book3" > </ref > </util:list >
1 2 3 <bean id ="bookShelf" class ="com.company.BookShelf" > <property name ="books" ref ="books" > </property > </bean >
1.3 工厂bean
对于工厂bean,配置文件中定义的bean类型可以和返回类型不一样
第一步:创建类,让这个类实现接口FactoryBean,作为工厂bean
第二步:实现接口声明的方法,在实现的方法中定义返回的对象类型,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class FacBean implements FactoryBean <Book > { @Override public Book getObject () throws Exception { Book book = new Book(); book.setName("C++ Primer" ); return book; } @Override public Class<?> getObjectType() { return Book.class; } @Override public boolean isSingleton () { return false ; } }
1 2 3 4 5 6 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" > <bean id ="book" class ="com.company.factorybean.FacBean" > </bean > </beans >
bean标签定义的类型为FacBean,但是实际getBean方法返回的对象类型是Book
1.4 bean的作用域
在Spring里面,默认情况下,bean是单实例对象
bean标签scope属性的取值,
是否单例
对象创建的时机
singleton
是
Spring加载配置文件时
prototype
否
调用getBean方法时
1.5 bean的生命周期 1.5.1 过程
通过构造器创建bean实例
调用set方法为bean的属性设置值和对其他bean引用
将bean对象传递给bean后置处理器的postProcessBeforeInitialization方法
调用bean的初始化方法(需要配置初始化方法)
将bean对象传递给bean后置处理器的postProcessAfterInitialization方法
bean可以被使用(对象获取到了)
当容器关闭时,调用bean的销毁方法(需要配置销毁的方法)
1.5.2 配置bean的初始化方法
1 2 3 public void initMethod () { System.out.println("step 4: call init method" ); }
在bean标签中使用init-method属性配置bean的初始化方法,
1 2 3 <bean id ="order" class ="com.company.cycle.Order" init-method ="initMethod" destroy-method ="destroyMethod" > <property name ="name" value ="laptop" > </property > </bean >
1.5.3 配置bean的销毁方法
1 2 3 public void destroyMethod () { System.out.println("step 7: call destroy method" ); }
在bean标签中使用destroy-method属性配置bean的销毁方法,
1 2 3 <bean id ="order" class ="com.company.cycle.Order" init-method ="initMethod" destroy-method ="destroyMethod" > <property name ="name" value ="laptop" > </property > </bean >
destroyMethod在容器关闭的时候被调用,
1 ((ClassPathXmlApplicationContext)context).close();
1.6 xml自动装配
假设存在Employee类和Department类,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public class Employee { private String name; private Department dept; public void setName (String name) { this .name = name; } public void setDept (Department dept) { this .dept = dept; } @Override public String toString () { return "Employee{" + "name='" + name + '\'' + ", dept=" + dept + '}' ; } } public class Department { private String name; public void setName (String name) { this .name = name; } @Override public String toString () { return "Department{" + "name='" + name + '\'' + '}' ; } }
1.6.1 按名字
在bean标签中将autowire属性配置为byName,
1 2 3 4 5 6 <bean id ="employee" class ="com.company.Employee" autowire ="byName" > <property name ="name" value ="Lihua" > </property > </bean > <bean id ="dept" class ="com.company.Department" > <property name ="name" value ="Tech" > </property > </bean >
1.6.2 按类型
bean标签中将autowire属性配置为byType,
1 2 3 4 5 6 <bean id ="employee" class ="com.company.Employee" autowire ="byType" > <property name ="name" value ="Lihua" > </property > </bean > <bean id ="dept" class ="com.company.Department" > <property name ="name" value ="Tech" > </property > </bean >
1.7 外部属性文件
使用“user.properties”配置文件初始化User对象,
1 2 3 4 user.name="Lihua" user.address="Beijing" user.telephone="123xxxxxxxx" user.favoriteBook="Hello, world!"
1 2 3 4 5 6 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:context ="http://www.springframework.org/schema/context" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd" >
1 2 3 4 5 6 7 8 <context:property-placeholder location ="classpath:user.properties" > </context:property-placeholder > <bean id ="user" class ="com.company.User" > <property name ="name" value ="${user.name}" > </property > <property name ="address" value ="${user.address}" > </property > <property name ="telephone" value ="${user.telephone}" > </property > <property name ="favoriteBook" value ="${user.favoriteBook}" > </property > </bean >
使用“$”符号引用外部配置文件的内容,必须保证大括号内和配置文件中的key一致
2 基于注解方式 2.1 Spring创建对象的注解
@Component,通用注解
@Service,通常用在Service层
@Controller,通常用在Web层
@Repository,通常用在DAO层
以上四个注解功能是一样的,都可以用来创建bean实例
2.2 创建对象 2.2.1 开启组件扫描
1 <context:component-scan base-package ="com.company.dao, com.company.service" > </context:component-scan >
1 <context:component-scan base-package ="com.company" > </context:component-scan >
2.2.2 添加注解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @Repository(value = "userDao") public class UserDao { @Override public String toString () { return "UserDao{}" ; } } @Service(value = "userService") public class UserService { UserDao userDao; public void setUserDao (UserDao userDao) { this .userDao = userDao; } @Override public String toString () { return "UserService{" + "userDao=" + userDao + '}' ; } }
注解括号内的value相当于xml配置文件bean标签的id属性
注解的value值可以不指定,默认值是将类名首字母小写
2.3 组件扫描配置 2.3.1 只扫描指定的注解 1 2 3 4 <context:component-scan base-package ="com.company" use-default-filters ="false" > <context:include-filter type ="annotation" expression ="org.springframework.stereotype.Service" /> <context:include-filter type ="annotation" expression ="org.springframework.stereotype.Repository" /> </context:component-scan >
默认情况下,Spring将扫描base-package包下所有的类
如果配置use-default-filters为false,那么Spring将根据配置进行组件扫描
使用context:include-filter标签可以指定将被扫描的注解
2.3.2 不扫描指定的注解 1 2 3 4 <context:component-scan base-package ="com.company" > <context:exclude-filter type ="annotation" expression ="org.springframework.stereotype.Component" /> <context:exclude-filter type ="annotation" expression ="org.springframework.stereotype.Controller" /> </context:component-scan >
使用context:exclude-filter标签可以指定某些注解不被扫描
2.4 注入属性 2.4.1 Autowired
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @Repository public class UserDaoImpl implements UserDao { @Override public void update () { System.out.println("UserDao update......" ); } } @Service(value = "userService") public class UserService { @Autowired UserDao userDao; public void setUserDao (UserDao userDao) { this .userDao = userDao; } @Override public String toString () { return "UserService{" + "userDao=" + userDao + '}' ; } }
在userDao属性上注解@Autowired,Spring将在组件扫描的包内搜寻符合条件的类型创建对象。在这个例子中,Spring找到UserDaoImpl是UserDao的实现类,符合条件
2.4.2 Qualifier
在上面的例子中,如果UserDao接口有多个实现类,仅通过@Autowired注解自动装配会产生冲突,因为Spring不知道该创建哪个实现类的对象
这个时候可以使用@Qualifier注解指定实现类,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @Repository public class UserDaoImpl2 implements UserDao { @Override public void update () { System.out.println("UserDao update......" ); } } @Service(value = "userService") public class UserService { @Autowired @Qualifier(value = "userDaoImpl2") UserDao userDao; public void setUserDao (UserDao userDao) { this .userDao = userDao; } @Override public String toString () { return "UserService{" + "userDao=" + userDao + '}' ; } }
@Qualifier注解括号内的value必须和实现类注解括号内的value相同
2.4.3 Value
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Repository public class UserDaoImpl1 implements UserDao { @Value(value = "Lihua") private String name; @Override public void update () { System.out.println("UserDao update......" ); } @Override public String toString () { return "UserDaoImpl1{" + "name='" + name + '\'' + '}' ; } }
2.5 完全注解开发 2.5.1 配置类
1 2 3 @Configurable @ComponentScan(basePackages = "com.company") public class SpringConfig {}
2.5.2 加载配置类,创建对象 1 2 3 ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); UserService service = context.getBean("userService" , UserService.class); System.out.println(service);
只需要将context的实现类替换成AnnotationConfigApplicationContext,将配置类的类型作为参数即可