1.1 IOC容器
Inversion of Control 控制反转容器。
作用: 解决对象创建以及管理问题。
解析:
传统关于对象创建:
User user = new User(); 自己控制对象的创建,自己声明变量管理对象引用。
IOC:
需要对象,自己不创建,交给IOC容器创建并管理,需要的时候从IOC容器中获取即可,这种情况就叫控制反转。
实现:
IOC容器 = ApplicationContext容器类 + bean.xml配置
1.2 DI 依赖注入
Dependency Injection 依赖注入。
创建对象处理依赖关系::就是指对象是被动接受依赖类而不是自己主动去找,换句话说就是指对象不是从容器中查找它依赖的类,而是在容器实例化对象的时候主动将它依赖的类注入给它。
User user = new User();
Address address = new Address();
user.setAddress(address);//依赖注入
2.1创建Bean的细节
<!-- 对象加入IOC容器 -->
<!-- 细节1:
id: 不能以数字开头,不能有特殊符号(符合java标识符的命名规则)
在IOC容器中id是不能重复
name:可以数字开头,可以有特殊符号。
描述的时候可以重复,但是实际使用还是会报错。
可以有多个,用逗号分隔
-->
<!-- 细节2:(单例/多例) 默认是单例
scope="prototype" 表示多例,每次获取都创建新的对象
singleton 默认值,表示单例
-->
<!-- 细节3: 声明周期
init-method:指定一个初始化方法。对象创建成功之后调用。
destroy-method: 指定一个销毁的方法。在IOC容器调用destroy()方法的时候调用,对单例对象才有效。
lazy-init: 延时初始化。
对单例对象有效,多例对象时无效。
单例对象默认在IOC容器创建的时候就创建出来。
多例对象在获取对象的时候才去创建。
如果希望在对象创建的时候不直接创建单例对象,而是在第一次使用单例对象的时候创建,就可以设置延时初始化
-->
<bean id="user" lazy-init="true" class="com.xinboedu.test2.User"
scope="singleton" init-method="init" destroy-method="destroy"/>
2.2 创建对象的几种方式
创建对象的几种方式 :
1) 调用无参数的构造方法
2) 调用有参数的构造方法,并通过构造方法赋值
3) 工厂模式( 静态工厂, 非静态工厂 )
4) 反射机制 (Spring IOC 原理就是反射机制)
class User {
private String name;
private int age;
public User(String name, int age) {
super();
this.name = name;
this.age = age;
}
public User() {
System.out.println("User被创建了!");
}
public void init() {
System.out.println("初始化方法~");
}
public void destroy() {
System.out.println("销毁的方法~");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + "]";
}
}
/
class UserFactory {
//非静态
public User getInstace() {
User user = new User();
user.setName("Jack");
user.setAge(20);
return user;
}
//静态
public static User getStaticInstace() {
User user = new User();
user.setName("Jack");
user.setAge(20);
return user;
}
public static User getStaticInstace(String name, int age) {
User user = new User();
user.setName(name);
user.setAge(age);
return user;
}
}
<!-- 1) 调用无参数的构造方法 -->
<bean id="user" class="com.xinboedu.test2.User"></bean>
<!-- 2) 调用有参数的构造方法 -->
<!--
constructor-arg:构造方法赋值参数
index: 赋值索引.不写的话按照默认顺序
type:说明参数类型。
value:要赋值的内容。字符串,会自动根据类型转换
ref: 应用容器中现有对象赋值
-->
<!-- String str = new String("Lynn") -->
<bean id="str" class="java.lang.String">
<constructor-arg value="Lynn"></constructor-arg>
</bean>
<bean id="user1" class="com.xinboedu.test2.User">
<constructor-arg index="0" type="String" ref="str"> </constructor-arg>
<constructor-arg index="1" type="int" value="18"> </constructor-arg>
</bean> -->
<!-- 3) 工厂模式 -->
<!-- 静态工厂: 不需要创建工厂对象 -->
<bean id="user2" class="com.xinboedu.test2.UserFactory" factory-method="getStaticInstace"></bean>
<!-- 非静态工厂:前提:有工程实例 -->
<bean id="userFactory" class="com.xinboedu.test2.UserFactory"></bean>
<bean id="user3" factory-bean="userFactory" factory-method="getInstace"></bean>
<!-- 指定参数的工厂 (相当于调用构造方法) -->
<bean id="user4" class="com.xinboedu.test2.UserFactory" factory-method="getStaticInstace">
<constructor-arg index="0" type="String" value="Lynn"> </constructor-arg>
<constructor-arg index="1" type="int" value="18"> </constructor-arg>
</bean>
/*反射机制*/
class App {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("root-context.xml");
AccountService accountService = context.getBean(AccountService.class);
System.out.println(accountService.sayHello());
context.close();
}
}
class App {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Class clazz = classLoader.loadClass("me.laiyijie.demo.service.AccountService");
Constructor constructor = clazz.getConstructor();
AccountService accountService = (AccountService) constructor.newInstance();
System.out.println(accountService.sayHello());
}
}
2.3 处理对象的依赖关系
给对象属性赋值(DI,依赖注入),几种方式:
1) 构造方法赋值
2) setter方法注入
3) 内部bean写法
4) p名称空间
5) 自动装配
6) 注解方式
<!-- 方式一: setter方法 -->
<bean id="userDao" class="com.xinboedu.test1.UserDao"></bean>
<bean id="userService" class="com.xinboedu.test1.UserService">
<property name="userDao" ref="userDao"></property>
</bean>
<bean id="userAction" class="com.xinboedu.test1.UserAction" scope="prototype">
<property name="userService" ref="userService"></property>
</bean>
<!-- 方式二: 内部bean -->
<!--
内部bean设置id外部也引用不了
外部bean是单例的话内部bean也是单例,外部多例,内部也多例
-->
<bean id="userAction" class="com.xinboedu.test1.UserAction" scope="prototype">
<property name="userService">
<bean class="com.xinboedu.test1.UserService">
<property name="userDao">
<bean class="com.xinboedu.test1.UserDao"></bean>
</property>
</bean>
</property>
</bean>
<!-- 方式三: p名称空间 -->
<!-- 前提: 在xml最上方加入p名称空间 -->
<bean id="userDao" class="com.xinboedu.test1.UserDao"></bean>
<bean id="userService" class="com.xinboedu.test1.UserService" p:userDao-ref="userDao"></bean>
<bean id="userAction" class="com.xinboedu.test1.UserAction" p:userService-ref="userService" scope="prototype"></bean>
<!-- 方式四: 自动转配 -->
<!--
(1)配置在指定的bean节点
autowire="byName" 根据名称在IOC容器中查询对应的名称赋值给当前对象的对应的setter()方法
byType 根据类型。 如果IOC容器中有两个同种类型的对象的话也报错。
(2)配置到整个xml文件
default-autowire="byType" xml中所有的bean节点都自动转配
-->
<bean id="userDao" class="com.xinboedu.test1.UserDao"></bean>
<bean id="userService" class="com.xinboedu.test1.UserService" ></bean>
<!-- <bean id="userAction" class="com.xinboedu.test1.UserAction" autowire="byType" scope="prototype"></bean> -->
<bean id="userAction" class="com.xinboedu.test1.UserAction" scope="prototype"></bean>
<!-- 方式五: 注解方式 -->
<!-- (1) context 名称空间 -->
<!-- (2) 开启注解扫描 (如果有多个包,号分隔) -->
<context:component-scan base-package="com.xinboedu.test1"></context:component-scan>
========================================================================
附:
list, set, map和props元素分别用来设置类型为List,Set,Map和Propertis的属性值。分别用来为bean传入集合值。
对应的spring的配置文件举例如下:
public class Chinese implements People ...{
private String name;
private int age;
private List friends = new ArrayList();
private Map score = new HashMap();
private Properties basicInfo = new Properties();
private Set interest = new HashSet();
// 省略对应set方法
.
}
<? xml version="1.0" encoding="gb2312" ?>
<! DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd" >
< beans >
< bean id ="chinese" class ="Chinese" >
<property name="name" value="123"></property>
<property name="age" value="18"></property>
<property name ="friends" >
< list >
< value > 张三 </ value >
< value > 李四 </ value >
< value > 王五 </ value >
</ list >
</property >
<property name ="score" >
< map >
< entry key ="数学" >
< value > 60 </ value >
</ entry >
< entry key ="英语" >
< value > 70 </ value >
</ entry >
< entry key ="语文" >
< value > 80 </ value >
</ entry >
< entry key ="物理" >
< value > 90 </ value >
</ entry >
< entry key ="化学" >
< value > 95 </ value >
</ entry >
</ map >
</property >
<property name ="basicInfo" >
< props >
< prop key ="身高" > 165 </ prop >
< prop key ="体重" > 45kg </ prop >
< prop key ="学历" > 大学本科 </ prop >
</ props >
</property >
<property name ="interest" >
< set >
< value > 唱歌 </ value >
< value > 跳舞 </ value >
< value > 书法 </ value >
</ set >
</property >
</bean >
</beans >