注意:为演示方便,所有class值都省略了包名
一、IoC(Inverse of Control)
IoC即控制反转,它是指将对象的创建权交给Spring容器管理
在开发中,我们经常遇到类A需要用到类B的场景,传统方式中我们往往在A中通过new显式的生成B实例,这样代码就产生了耦合。使用Spring框架后,我们可以通过配置将类注册到Spring容器中,容器再借助反射等机制为我们提供对象。
请看下面这个例子:
public class Person {
public void say() {
System.out.println("Hello Spring!");
}
}
在resources文件夹下配置applicationContext.xml文件:
<bean id="person" class="Person"/>
使用Spring工厂类获得对象:
// 创建Spring的工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过工厂获得类
UserService userService = (UserService) applicationContext.getBean("person");
userService.say(); // 成功打印Hello Spring!
二、DI(Dependency Injection)
DI即依赖注入,它是指在Spring托管对象的过程中,将该对象所依赖的属性注入进去。
请看这个例子:
public class Person {
// 属性:姓名、工作
private String name;
private Job job;
public Person() {
}
public Person(String name, Job job) {
this.name = name;
this.job = job;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Job getJob() {
return job;
}
public void setJob(Job job) {
this.job = job;
}
}
public class Job {
// 属性:工作名称
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
现在,我们欲创建一组对象:Person{name=‘小明’, job=Job{name=‘研发工程师’}}
1. 通过构造器注入
<bean id="person" class="Person">
<constructor-arg name="name" value="小明"/>
<constructor-arg name="job" ref="job"/>
</bean>
<bean id="job" class="Job">
<property name="name" value="研发工程师"/>
</bean>
2. 通过set方法注入
在resources文件夹下配置applicationContext.xml文件:
<bean id="person" class="Person">
<property name="name" value="小明"/>
<property name="job" ref="job"/>
</bean>
<bean id="job" class="Job">
<property name="name" value="研发工程师"/>
</bean>
3. 通过p命名空间注入
p命名空间是Spring2.5新增的注入方法,在使用前需在applicationContext.xml的头部中增加一行约束:xmlns:p="http://www.springframework.org/schema/p"
<bean id="person" class="Person" p:name="小明" p:job-ref="job"/>
<bean id="job" class="Job" p:name="研发工程师"/>
4. 通过SpEL注入
SpEL(Spring Expression Language)即Spring表达式,编写者可以在表达式中调用其它类的某个方法,并将它的返回值作为参数值注入,也可以直接传入字符串。
为演示方便,新增一个工厂类:
public class JobFactory {
public static Job createJob() {
Job job = new Job();
job.setName("研发工程师");
return job;
}
}
<bean id="jobFactory" class="JobFactory"/>
<bean id="person" class="Person">
<property name="name" value="#{'小明'}"/>
<property name="job" value="#{jobFactory.createJob()}"/>
</bean>
* 5. 复杂类型的注入
该例是针对数组、集合的属性注入:
public class Data {
private String[] arr;
private List<String> list;
private Set<String> set;
private Map<Integer, String> map;
public String[] getArr() {
return arr;
}
public void setArr(String[] arr) {
this.arr = arr;
}
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
public Set<String> getSet() {
return set;
}
public void setSet(Set<String> set) {
this.set = set;
}
public Map<Integer, String> getMap() {
return map;
}
public void setMap(Map<Integer, String> map) {
this.map = map;
}
}
配置applicationContext.xml文件:
<bean id="data" class="Data">
<property name="arr">
<list>
<value>arr1</value>
<value>arr2</value>
<value>arr3</value>
</list>
</property>
<property name="list">
<list>
<value>list1</value>
<value>list2</value>
<value>list3</value>
</list>
</property>
<property name="set">
<set>
<value>set1</value>
<value>set2</value>
<value>set3</value>
</set>
</property>
<property name="map">
<map>
<entry key="1" value="map1"/>
<entry key="2" value="map2"/>
<entry key="3" value="map3"/>
</map>
</property>
</bean>
最终Data对象中的信息:Data{arr=[arr1, arr2, arr3], list=[list1, list2, list3], set=[set1, set2, set3], map={1=map1, 2=map2, 3=map3}}
三、Bean的作用域
默认情况下,Spring托管对象都是以单例模式(singleton)创建的
// 创建Spring的工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过工厂获得类
UserService userService1 = (UserService) applicationContext.getBean("userService");
UserService userService2 = (UserService) applicationContext.getBean("userService");
System.out.println(userService1 == userService2); // 输出true
我们可以在applicationContext.xml中进行修改配置,来实现多例模式(prototype):
<bean id="userService" class="UserServiceImpl" scope="prototype"/>
再次运行上述代码,将打印false,说明userService1和userService2是两个不同的对象。
四、Bean的生命周期
该图片转载自网络
生命周期中的BeanPostProcessor阶段主要用于Spring AOP
我们可以手工配置Spring创建和销毁对象时所要执行的init-method和destroy-method,请看示例:
public class Person {
public Person() {
System.out.println("===构造方法===");
}
public void init() {
System.out.println("===初始化方法===");
}
public void destroy() {
System.out.println("===销毁方法===");
}
}
在resources文件夹下配置applicationContext.xml文件:
<bean id="person" class="Person" init-method="init" destroy-method="destroy"/>
五、注解方式的实现
1. IoC
注释 | 针对场合 |
---|---|
@Conponent | 传统组件,可用于任何Bean |
@Repository | 适用于持久层 |
@Service | 适用于业务层 |
@Controller | 适用于表现层 |
示例:
①首先在配置文件中开启注解扫描
<context:component-scan base-package="完整包名"/>
②然后对需要托管的类增加注解
@Component("person")
public class Person {
public void say() {
System.out.println("Hello Spring!");
}
}
③最后在具体场景中通过Spring工厂类获取实例
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) applicationContext.getBean("person");
person.say(); // 成功打印Hello Spring!
2. DI
注解 | 特点 |
---|---|
@Value | 注入字符串或其它的值 |
@Autowired | 注入类(只根据类型匹配) |
@Autowired + @Qualifier | 注入类(根据类型以及名字进行匹配) |
@Resource | 注入类(根据类型以及名字进行匹配) |
示例:
@Service("userService")
public class UserService {
@Resource(name = "userDao")
private UserDao userDao;
public void save() {
userDao.save();
}
}
@Repository("userDao")
public class UserDao {
public void save() {
System.out.println("=====UserDao保存=====");
}
}
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) applicationContext.getBean("userService");
userService.save(); // 成功打印=====UserDao保存=====
3. 作用域
注解 | 含义 |
---|---|
@Scope | 同scope,默认sington,可选prototype |
@Component("person")
@Scope("prototype")
public class Person {
}
4. 生命周期
注解 | 含义 |
---|---|
@PostConstruct | init-method |
@PreDestroy | destroy-method |
示例:
@Component("person")
public class Person {
@PostConstruct
public void init() {
System.out.println("======初始化======");
}
@PreDestroy
public void destory() {
System.out.println("======销毁======");
}
}
六、XML + 注解混合
XML文件清晰集中,便于查看和管理,而注解方式使用便捷高效,在实际开发场景中,两者可以混合运用,利用XML管理Bean,利用注解实现属性注入。
①首先在配置文件中开启属性注入的注解
(本配置仅开启属性注入的部分,而例五中的设置则开启了全部)
<context:annotation-config/>
②然后在类的属性上进行注入
public class Person {
@Value("小明")
private String name;
@Value("18")
private String age;
@Value("研发工程师")
private String job;
}
③接着在配置文件中进行Person类的配置
<bean id="person" class="com.imooc.ioc.Person"/>
最终构建了一组对象:Person{name=‘小明’, age=‘18’, job=‘研发工程师’}
附:要使用Spring框架,需要引入下列4个jar包
spring-core、spring-context、spring-beans、spring-expression