Spring学习笔记-IOC
IOC理论推导
原来的一个业务开发流程:
-
UserDao 数据访问接口
public interface UserDao{ void getUser(); }
-
UserDaoImpl 数据访问实现类
public class UserDaoImpl implements UserDao{ @Override public void getUser(){ SyStem.out.println("获取到普通用户"); } }
public class UserDaoSuperImpl implements UserDao{ @Override public void getUser(){ System.out.println("获取到超级用户"); } }
-
UserService 业务接口
public interface UserService{ void getUser(); }
-
UserServiceImpl 业务实现类
public class UserServiceImpl implements UserService{ private UserDao userDao = new UserDaoImpl(); // private UserDao userDao = new UserDaoSuperImpl(); @Override public void getUser(){ userDao.getUser(); } }
-
测试类
public class MyTest{ public static void main(String[] args){ UserService userService = new UserServiceImpl(); userService.getUser(); } }
那么在我们原来的代码中,用户的需求可能会影响我们原来的代码,也即用户的需求每发生一次变更,我们就要去修改一次源代码,但如果代码量十分庞大,修改一次的代价也十分昂贵,比如如上述代码,当我们需要获取一个普通用户的时候,我们需要去new一个UserDaoImpl,而当我们需要一个超级用户的时候,又得去更改我们new的实例
而当我们在UserServiceImpl中将获取userDao实例的方式修改之后:
private UserDao userDao;
public void setUserDao(UserDao userDao){this.UserDao = userDao;}
此时我们再来使用测试类来获取不同级别的用户,我们就可以通过只修改注入的不同实例来实现我们的需求:
public class MyTest{
public static void main(String[] args){
UserService userService = new UserServiceImpl();
((UserServiceImpl)userService).setUserDao(new UserDaoImpl());
// ((UserServiceImpl)userService).setUserDao(new UserDaoSuperImpl());
userService.getUser();
}
}
那么两者的区别在哪呢?
- 前者的方式,程序都是主动创建对象,控制权在程序员手上
- 使用了set注入后,程序不再具有主动性,而是变成了被动的接收对象
而在这种思想上,从本质解决了问题,程序员也不用再去管理对象的创建了,系统的耦合性大大降低,可以更加专注于再业务的实现上,而这就是IOC的原型
IOC本质
控制反转(IOC)是一种设计思想,**而DI(依赖注入)**是实现IOC的一种方式。在没有IOC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由自己控制;而在控制反转后则将对象的创建转移给第三方,如在Spring中的IOC容器(applicationContext),而在Spring中IOC的底层实现原理就是反射+工厂方法模式,使得获得依赖对象的方式反转了
Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从IOC容器中取出需要对象
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到零配置的目的
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中,实现控制反转的是IOC容器,其实现方法是依赖注入(DI)
代码实现
-
实体类
public class Hello { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Hello{" + "name='" + name + '\'' + '}'; } }
-
applicationContext.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"> <!--使用Spring来创建,在Spring中,这些都称为bean 类型 变量名 = new 类型() Hello hello = new Hello() id:变量名 class:new的对象 property:相当于给对象设置一个值 ref:引用Spring容器中创建好的对象 value:具体的值 --> <bean id="hello" class="com.alb.pojo.Hello"> <property name="name" value="Alb"/> </bean> </beans>
-
测试类
public class MyTest { public static void main(String[] args) { // 获取Spring的上下文对象 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 我们的对象都在Spring中管理了,如果要使用,直接取出来就可以 Hello hello = (Hello) context.getBean("hello"); System.out.println(hello.toString()); } }
IOC创建对象的方式
-
默认使用无参构造器创建对象
User实体类
public class User { private String name; public User(){ System.out.println("User的无参构造"); } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "name='" + name + '\'' + '}'; } }
applicationContext.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 id="user" class="com.alb.pojo.User"> <property name="name" value="Alb"/> </bean> </beans>
测试类
public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); User user = (User) context.getBean("user"); System.out.println(user.toString()); } }
结果
-
有参构造器
// User实体类 public class User { private String name; public User(String name){ this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "name='" + name + '\'' + '}'; } }
applicationContext.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 id="user" class="com.alb.pojo.User"> <constructor-arg index="0" value="Alb"/> </bean> <!--第二种方式,通过类型创建,不建议使用--> <bean id="user" class="com.alb.pojo.User"> <constructor-arg type="java.lang.String" value="Albb"/> </bean> <!--通过参数名创建--> <bean id="user" class="com.alb.pojo.User"> <constructor-arg name="name" value="Albe"/> </bean> </beans>
在配置文件加载的时候,容器中管理的对象就已经初始化了