上述是spring框架组成的模块,它的核心容器有BeanFacory,通过IOC模式使应用程序的配置和依赖与实际的应用程序分开。
一. 什么是IOC
先看一个demo
public interface UserDao {
public void getUser();
}
public class UserDaoImpl implements UserDao {
@Override
public void getUser() {
System.out.println("获取用户数据");
}
}
上述两个是Dao层做事情,然后看service层调用
public interface UserService {
public void getUser();
}
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
现在写一个测试类,通过直接拿service层的东西
@Test
public void test(){
UserService service = new UserServiceImpl();
service.getUser();
}
如果现在需求改了,需要我们在dao层的时候加上一个实现类
public class UserDaoMySqlImpl implements UserDao {
@Override
public void getUser() {
System.out.println("MySql获取用户数据");
}
}
这个时候如果要是使用这个实现类的话,那么service层必须修改里面的实现,也就是改成如下:
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoMySqlImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
但是这个时候程序实际上不满足尽量少修改,多扩展原则,于是可以使用set,在业务层的实现类中修改代码如下
public class UserServiceImpl implements UserService {
private UserDao userDao;
// 利用set实现
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
这样,给我们留一个UserDao接口,当我们即使再增加一个oracle实现类,我还是一样可以把它set进去,然后取出它实现类的方法。
@Test
public void test(){
UserServiceImpl service = new UserServiceImpl();
service.setUserDao( new UserDaoMySqlImpl() );
service.getUser();
//那我们现在又想用Oracle去实现呢
service.setUserDao( new UserDaoOracleImpl() );
service.getUser();
}
以上的例子实现了我们自行控制创建对象,把主动权交给了我们自己,程序负责提供一个接口。
而IOC它是对象的创建与对象之间的依赖关系完全移交给第三方,可以由配置文件XML或者注解实现
二.通过spring来实现IOC
spring的基于配置文件的IOC
2.1. 依赖的包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
2.2. 实体类
public class Hello {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("Hello,"+ name );
}
}
2.3. 配置文件,这个在resource包下面写一个beans.xml
<?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就是java对象 , 由Spring创建和管理-->
<bean id="hello" class="com.kuang.pojo.Hello">
<property name="name" value="Spring"/>
</bean>
</beans>
- 测试
@Test
public void test(){
//解析beans.xml文件 , 生成管理相应的Bean对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//getBean : 参数即为spring配置文件中bean的id .
Hello hello = (Hello) context.getBean("hello");
hello.show();
}
三.IOC创建对象的方式
3.1无参构造方法
这个实际上就是实体类要有无参构造,这样的话,beans.xml才可以使用bean标签来配置
3.2有参构造方法
public class UserT {
private String name;
public UserT(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name="+ name );
}
}
主要通过参数类型或者参数名字来设置
<!-- 第二种根据参数名字设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
<!-- name指参数名 -->
<constructor-arg name="name" value="kuangshen2"/>
</bean>
<!-- 第三种根据参数类型设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
<constructor-arg type="java.lang.String" value="kuangshen2"/>
</bean>
有一个需要注意的就是配置文件加载的时候,ioc容器里面所有的对象都已经初始化了,可以通过重写无参构法来查看
四.依赖注入
Dependency Injection是spring框架核心ioc的具体实现,就是把这种依赖通过注入来降低系统的耦合,让spring去维护。
4.1.使用构造函数的方式来注入:
使用类中的构造函数,给成员变量赋值:其中赋值的操作不是我们做的,而是通过配置的方式,让spring框架来为我们注入
public class AccountServiceImpl implements IAccountService {
private String name;
private Integer age;
private Date birthday;
public AccountServiceImpl(String name, Integer age, Date birthday) {
this.name = name;
this.age = age;
this.birthday = birthday; }
@Override public void saveAccount() {
System.out.println(name+","+age+","+birthday); }
}
使用构造函数的方式,给 service 中的属性传值 要求: 类中需要提供一个对应参数列表的构造函数。 配置中涉及的标签:
constructor-arg
属性: index:指定参数在构造函数参数列表的索引位置
type:指定参数在构造函数中的数据类型
name:指定参数在构造函数中的名称 用这个找给谁赋值
上面三个都是找给谁赋值,下面两个指的是赋什么值的
value:它能赋的值是基本数据类型和 String 类型
ref:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<constructor-arg name="name" value=" 张三 "></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="birthday" ref="now"></constructor-arg> </bean>
<bean id="now" class="java.util.Date"></bean> //因为这个赋值的类型不是基本类型和Stirng类型
4.2.使用set方法注入
就是在类中提供需要注入成员的set方法
public class AccountServiceImpl implements IAccountService {
private String name;
private Integer age;
private Date birthday;
public void setName(String name) {
this.name = name; }
blic void setAge(Integer age) {
this.age = age; }
public void setBirthday(Date birthday) {
this.birthday = birthday; }
@Override public void saveAccount() { System.out.println(name+","+age+","+birthday); } }
这个时候配置文件给bean中的属性传值:使用set方法的方式:
涉及的标签有property
属性:
name:找的就是set方法后面的部分(首字母小写)
ref:给属性赋值时其他bean类型的
value:给属性赋值是基本数据类型和String类型
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<property name="name" value="test"></property>
<property name="age" value="21"></property>
<property name="birthday" ref="now"></property> </bean>
<bean id="now" class="java.util.Date"></bean>
4.3. 使用p或者c名称空间注入数据
首先需要在beans.xml中引入约束
<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"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
然后在p命名空间针对的是一定要有无参构造器
<bean id="userBean" class="zhang.pojo.User" p:name="zhang" p:age="23"/>
c命名空间针对的是一定要有无参构造器
<bean id="user2" class="zhang.pojo.User" c:age="18" c:name="xiao"/>
4.4 .注入集合属性
这里注入的变量的数据类型都是集合,List,Set,Map,Properties
public class AccountServiceImpl implements IAccountService {
private String[] myStrs;
private List<String> myList;
private Set<String> mySet;
private Map<String,String> myMap;
private Properties myProps;
public void setMyStrs(String[] myStrs) {
this.myStrs = myStrs; }
public void setMyList(List<String> myList) {
this.myList = myList; }
public void setMySet(Set<String> mySet) {
this.mySet = mySet; }
public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap; }
public void setMyProps(Properties myProps) {
this.myProps = myProps; }
@Override public void saveAccount() {
System.out.println(Arrays.toString(myStrs));
System.out.println(myList);
System.out.println(mySet);
System.out.println(myMap); }
*注入集合数据,这里首先要分成两大类
List结构:
array,list,set
Map结构:
map,entry,props,prop*
<!-- 给set注入数据 -->
<property name="myStrs">
<set> <value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</set>
</property>
<!-- 注入 array 集合数据 -->
<property name="myList">
<array> <value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</array> </property>
<!-- 注入 list 集合数据 -->
<property name="mySet">
<list> <value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</list> </property>
<!-- 注入 Map 数据 -->
<property name="myMap">
<props>
<prop key="testA">aaa</prop>
<prop key="testB">bbb</prop>
</props>
</property>
<!-- 注入 properties 数据 -->
<property name="myProps">
<map>
<entry key="testA" value="aaa"></entry>
<entry key="testB">
<value>bbb</value> </entry> <
/map>
</property>
</bean>