Inversion of Control的缩写,中文译为控制反转,简单来水就是把对象创建和对象之间的调用过程,交给 Spring 进行管理。
创建对象实例的控制权从代码控制剥离到IOC容器控制,实际就是你在xml文件控制,侧重于原理
Class clazz=Class.forName(classValue);
UserService service=clazz.newInstance();
return service;
<bean id="user" class="com.spring5.User">
<property name="name" value="小明">property>
bean>
<bean id="user" class="com.spring5.User">
<constructor-arg name="name" value="张三">constructor-arg>
bean>
<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.spring5.User" p:name="李四">bean>
beans>
<property name="name">
<null>null>
property>
方法一 把<>进行转义
<property name="name" value="<<王五>>">
</property>
把带特殊符号内容写到 CDATA
<property name="name">
<value>>]]>value>
property>
现有类UserService、接口UserDao、类UserDaoImpl,其中UserDaoImpl实现了接口UserDao。代码结构如下:
src
│ bean.xml
│
└─com
└─spring5
│ Test.java
│
├─dao
│ UserDao.java
│ UserDaoImpl.java
│
└─service
UserService.java
如果类UserService要调用类UserDaoImpl的方法,传统做法是创建UserDao对象然后调用其方法,这种做法耦合太高。用spring注入的步骤如下:
示例代码如下:
接口UserDao:
public interface UserDao {
public void update();
}
类UserDaoImpl:
public class UserDaoImpl implements UserDao {
@Override
public void update() {
System.out.println("I am dao update...");
}
}
类UserService:
public class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Test
public void add(){
System.out.println("I am service add...");
userDao.update();
}
}
bean.xml:
<bean id="userDaoImpl" class="com.spring5.dao.UserDaoImpl">bean>
<bean id="userService" class="com.spring5.service.UserService">
<property name="userDao" ref="userDaoImpl">
property>
bean>
简单来说就是bean标签里面嵌套bean标签。在员工和部门,一个部门有多个员工,一个员工属于一个部门。示例代码如下:
Dept类:
public class Dept {
private String dname;
public void setDname(String dname) {
this. dname = dname;
}
}
Emp类
public class Emp {
private String ename;
private String gender;
//员工属于某一个部门,使用对象形式表示
private Dept dept;
public void setDept(Dept dept) {
this. dept = dept;
}
public void setEname(String ename) {
this. ename = ename;
}
public void setGender(String gender) {
this. gender = gender;
}
}
property>
property>
property>
bean>
property>
bean>
Emp类需要生成getDep的方法
public Dept getDept(){
return dept;
}
XML文件中dept.dname获取属性
property>
property>
property>
bean>
新建类User,包含集合属性和相关set方法
public class User {
private String[] arrs;// 数组
private List<String> list;// list
private Map<String,String> maps;// map
private Set<String> sets;// set
public void setArrs(String[] arrs) {
this.arrs = arrs;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
public void setSets(Set<String> sets) {
this.sets = sets;
}
}
XML配置
<array>
<value>JAVA课程value>
<value>mySQL课程value>
array>
property>
<list>
<value>张三value>
<value>李四value>
list>
property>
<map>
entry>
entry>
map>
property>
<set>
<value>MySQLvalue>
<value>MySQLvalue>
<value>Oraclevalue>
<value>Oraclevalue>
set>
property>
bean>
Dept类
public class Dept {
//部门有多个员工
private List<Emp> empList;
public void setEmpList(List<Emp> empList) {
this.empList = empList;
}
}
Emp类
public class Emp {
private String eName;
public void seteName(String eName) {
this.eName = eName;
}
}
XML配置
<property name="empList">
<list>
<ref bean="emp1">ref>
<ref bean="emp2">ref>
<ref bean="emp3">ref>
list>
property>
bean>
<bean id="emp1" class="com.spring5.Emp">
<property name="eName" value="张三">property>
bean>
<bean id="emp2" class="com.spring5.Emp">
<property name="eName" value="李四">property>
bean>
<bean id="emp3" class="com.spring5.Emp">
<property name="eName" value="王五">property>
bean>
Spring可以根据属性名称或者类型进行自动装配,使用byType时相同类型的Bean不能配置多个。
bean>
bean>
一、创建外部属性文件jdbc.properties,填写数据库信息,key随便写
prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/userDb
prop.userName=root
prop.password=root
二、把外部 properties 属性文件引入到 spring 配置文件中
引入 context 名称空间
xmlns:context=“http://www.springframework.org/schema/context”
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring- - context.xsd"
在 spring 配置文件使用标签引入外部属性文件
<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">
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}">property>
<property name="url" value="${prop.url}">property>
<property name="username" value="${prop.userName}">property>
<property name="password" value="${prop.password}">property>
bean>
beans>
Spring 有两种类型:普通 bean和工厂bean(FactoryBean)。普通 bean在配置文件中定义的bean类型和返回类型一样,而工厂bean在配置文件定义 bean类型可以和返回类型不一样。实现工厂Bean的步骤如下:
示例代码如下:
MyBean和User类
public class MyBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
User user = new User();
user.setName("张三");
return user;
}
@Override
public Class<User> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
public class User {
private String name;
public void setName(String name) {
this.name = name;
}
public void test(){
System.out.println("I am test...");
}
}
bean.xml
<bean id="myBean" class="com.spring5.MyBean">bean>
Test类
public class Test {
@org.junit.Test
public void test() {
//1 加载 spring 配置文件
ApplicationContext context =
new ClassPathXmlApplicationContext("bean.xml");
//2 获取配置创建的对象
User user = context.getBean("myBean", User.class);
System.out.println(user);
user.test();
}
}
运行结果:
com.spring5.User@42d8062c
I am test…
作用域 | 说明 |
---|---|
单例(singleton) | 默认)每一个Spring IoC容器都拥有唯一的一个实例对象 |
原型(prototype) | 一个Bean定义,任意多个对象 |
请求(request) | 一个HTTP请求会产生一个Bean对象,也就是说,每一个HTTP请求都有自己的Bean实例。只在基于web的Spring ApplicationContext中可用 |
会话(session) | 限定一个Bean的作用域为HTTPsession的生命周期。同样,只有基于web的Spring ApplicationContext才能使用 |
全局会话(global session) | 限定一个Bean的作用域为全局HTTPSession的生命周期。通常用于门户网站场景,同样,只有基于web的Spring ApplicationContext可用 |
第一步,执行无参构造创建Bean实例
第二步,调用类的set方法设置属性值
第三步,调用预初始化方法postProcessBeforeInitialzation()
需要有Bean实现了BeanPostProcessor接口
第四步,调用bean的初始化的方法
需要在XML的bean属性中进行配置
init-method="初始化调用方法名"
第五步,调用后初始化方法postProcessAfterInitialization()
需要有Bean实现了BeanPostProcessor接口
第六步,对象获取到了,bean可以使用了
第七步,当容器关闭时调用bean的销毁的方法
需要在XML的bean属性中进行配置
destroy-method="销毁调用方法名"
实例代码如下:
User类
public class User {
private String name;
public User() {
System.out.println("第一步 执行无参构造创建Bean实例");
}
public void setName(String name) {
this.name = name;
System.out.println("第二步 调用set方法设置属性值");
}
public void initMethod(){
System.out.println("第四步 调用bean的初始化的方法");
}
public void destroyMethod(){
System.out.println("第七步 当容器关闭时调用bean的销毁的方法");
}
public void test(){
System.out.println("I am test...");
}
}
MyBeanPost类
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("第三步,调用预初始化方法postProcessBeforeInitialzation()");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("第五步,调用后初始化方法postProcessAfterInitialization()");
return bean;
}
}
Test类
public class Test {
@org.junit.Test
public void test() {
//1 加载 spring 配置文件
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("bean.xml");
//2 获取配置创建的对象
User user = context.getBean("user", User.class);
System.out.println(user);
System.out.println("第六步 对象获取到了,bean可以使用了");
user.test();
context.close();
}
}
bean.xml
<!--配置User对象-->
<bean id="user" class="com.spring5.User" init-method="initMethod" destroy-method="destroyMethod">
<!--name的值对应于javaBean中的属性值-->
<property name="name" value="小明"></property>
</bean>
<bean id="myBeanPost" class="com.spring5.MyBeanPost"></bean>
<context:component-scan base-package="com.spring5">context:component-scan>
@Component(value = "userService")
public class UserService {
public void add(){
System.out.println("I am UserService add...");
}
}
示例一
<context:component-scan base-package="com.spring5" use-default-filters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
context:component-scan>
示例二
<context:component-scan base-package="com.spring5">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
context:component-scan>
@Autowired、@Qualifier和@Resource用于"对象"属性,@Value用于普通属性。
现有类UserService、接口UserDao、类UserDaoImpl,其中UserDaoImpl实现了接口UserDao。代码结构如下:
src
│ bean.xml
│
└─com
└─spring5
│ Test.java
│
├─dao
│ UserDao.java
│ UserDaoImpl.java
│
└─service
UserService.java
如果类UserService要调用类UserDaoImpl的方法,用spring注解实现的步骤如下:
示例代码如下:
接口UserDao:
public interface UserDao {
public void update();
}
类UserDaoImpl:
@Repository(value = "userDaoImpl")
public class UserDaoImpl implements UserDao {
@Override
public void update() {
System.out.println("I am dao update...");
}
}
类UserService:
@Service(value = "userService")
public class UserService {
@Autowired
private UserDao userDao;
public void add(){
System.out.println("I am UserService add...");
userDao.update();
}
}
bean.xml:
<context:component-scan base-package="com.spring5">
context:component-scan>
@Qualifier注解是根据名称进行注入。如果接口有很多实现类用@Autowired就不行,和@Qualifier一起使用就可以解决。使用示例:
@Autowired
@Qualifier(value = "userDaoImpl2")
private UserDao userDao;
@Resource是javax.annotation.Resource包中的注解,既可以根据名称注入又可以根据类型注入。
示例:
// 根据类型注入
@Resource
private UserDao userDao;
// 根据名称注入
@Resource(name = "userDaoImpl")
private UserDao userDao;
@Value用于普通属性。
@Value(value = "张三丰")
private String name;
步骤如下:
my.names=zhangsan,lisi,wangwu,zhaoli
@Service(value = "userService")
@PropertySource(value="classpath:application.properties")
public class UserService {
@Resource(name = "userDaoImpl")
private UserDao userDao;
@Value("#{'${my.names}'.split(',')}")
private List<String> names;
public void add(){
System.out.println("I am UserService add...");
userDao.update();
}
}
参考链接
@Configuration
@ComponentScan(basePackages = {
"com.spring5"})
public class SpringConfig {
}
@org.junit.Test
public void test() {
//1 加载spring的java配置文件
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
//2 获取创建的对象
UserService userService = context.getBean("userService", UserService.class);
userService.add();
}
这个过程在实际环境中会用SpringBoot替代。