推理过程
定义接口,获取用户的方法:
package com.lx.dao;
public interface UserDao {
void getUser();
}
创建UserDaoImpl类实现UserDao的接口,里面能够调用默认获取用户的方法
package com.lx.dao;
public class UserDaoImpl implements UserDao{
public void getUser() {
System.out.println("Dao层默认获取用户数据的方法");
}
}
在服务层创建接口,获取用户的方法:
package com.lx.service;
public interface UserService {
void getUser();
}
在服务层创建UserServiceImpl类实现上接口:
package com.lx.service;
import com.lx.dao.UserDao;
public class UserServiceimpl implements UserService {
private UserDaoImpl user = new UserDaoImpl();
public void getUser() {
System.out.println("在service层调用dao层获取user");
user.getUser();
}
}
测试单元:
@Test
public void test(){
UserService user = new UserServiceimpl();
user.getUser();
}
测试结果:
<
在持久层里有一个类(UserDaoImpl),类中有一个是默认获取用户数据的方法(getUser),简称A方法,
想要使用A方法,需要在service层调用dao层的方法,于是在类中(UserServiceImpl)中创建了一个有该方法的dao层对象,通过调用A方法,并将其封装到当前(UserServiceImpl)类中的方法中
在测试单元中,通过创建service层的对象,调用该对象封装好的方法,就可以调用dao层的A方法,用户通过调用service层而无需直接调用dao层,即可使用A方法
如果此时新增一个方法是使用mysql的方法:
package com.lx.dao;
public class UserDaoMysqlimpl implements UserDao{
public void getUser() {
System.out.println("Dao层Mysql获取用户数据");
}
}
虽然方法名相同,但是实现需要修改业务层的代码,
private UserDao userDao = new UserDaoMysqlimpl();
public void getUser() {
System.out.println("在service层调用dao层获取user");
userDao.getUser();
}
在这里理解,都是获取用户的方法,但只是方式不同,使用不同的方式却需要修改大量的…代码
像一个办法,将主动权交给用户,而不是业务层
再新增一个Oracle方式获取user的方法
package com.lx.dao;
public class UserDaoOrcleimpl implements UserDao{
public void getUser() {
System.out.println("Dao层获取用户orcle的方法");
}
}
在业务层,通过set可以实现动态的注入
package com.lx.service;
import com.lx.dao.UserDao;
import com.lx.dao.UserDaoImpl;
import com.lx.dao.UserDaoMysqlimpl;
public class UserServiceimpl implements UserService {
private UserDao userDao ;
//利用set进行动态实现值的注入!
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void getUser() {
System.out.println("在service层调用dao层获取user");
userDao.getUser();
}
}
这样就可以利用set注入的方式,将主动权给了用户,用户想用什么样的方式就创建什么样的对象,通过set方法调用合适的方法
测试单元:
@Test
public void test2(){
UserServiceimpl userServiceimpl = new UserServiceimpl();
userServiceimpl.setUserDao(new UserDaoImpl());
userServiceimpl.getUser();
System.out.println("=============");
userServiceimpl.setUserDao(new UserDaoMysqlimpl());
userServiceimpl.getUser();
System.out.println("==============");
userServiceimpl.setUserDao(new UserDaoOrcleimpl());
userServiceimpl.getUser();
}
- 以前所有东西都是由程序去进行控制创建 , 而现在是由我们自行控制创建对象 , 把主动权交给了调用者 . 程序不用去管怎么创建,怎么实现了它只负责提供一个接口 .
- 这种思想 , 从本质上解决了问题 , 我们程序员不再去管理对象的创建了 , 更多的去关注业务的实现 . 耦合性大大降低 .这也就是IOC的原型 !
IOC本质
控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认
为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系
完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为
所谓控制反转就是:获得依赖对象的方式反转了。
IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,
新版本的Spring也可以零配置实现IoC。
Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用
时再从Ioc容器中取出需要的对象。
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为
一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现
控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
Hello Spring
先理解ioc的本质,创建第一个spring
创建一个Hello实体类:
里面有属性str
str的get set方法
toStrng方法 helloWord方法
package com.lx.pojo;
public class Hello {
private String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
@Override
public String toString() {
return "Hello{" +
"str='" + str + '\'' +
'}';
}
public void helloWord() {
System.out.println("Hello Spring ! hello Word !");
}
}
resource目录下创建beans.xml配置文件
配置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 相当于给对象中的属性设置一个值!
-->
<bean id="hello" class="com.lx.pojo.Hello">
<property name="str" value="Hello Spring"/>
</bean>
</beans>
测试类:
import com.lx.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Mytest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//我们的对象现在都在Spring中的管理了,我们要使用,直接去里面取出来就可以!
// Hello hello = (Hello) context.getBean("hello");
Hello hello = context.getBean("hello",Hello.class);
System.out.println(hello.toString());
hello.helloWord();
}
}
测试结果:
配置分析:
bean就是java对象 , 由Spring创建和管理
id = 变量名
class = new 的对象;
property 相当于给对象中的属性设置一个值!
ref : 引用Spring容器中创建好的对象
而在上述例子中的hello对象:
【 hello 对象是由Spring创建的 】
【hello 对象的属性是由Spring容器设置的 】
!!! 对象的属性通过propetry赋值时,必须要有该属性的set get方法
在spring中新增一个小例子 nohello
<?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 相当于给对象中的属性设置一个值!
-->
<bean id="hello" class="com.lx.pojo.Hello">
<property name="str" value="Hello Spring"/>
</bean>
<bean id="nohello" class="com.lx.pojo.Hello">
<property name="str" value="fuck Spring"/>
</bean>
</beans>
通过id = nohello 创建一个新的对象
import com.lx.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Mytest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//我们的对象现在都在Spring中的管理了,我们要使用,直接去里面取出来就可以!
// Hello hello = (Hello) context.getBean("hello");
Hello hello = context.getBean("hello",Hello.class);
System.out.println(hello.toString());
hello.helloWord();
System.out.println("====================");
Hello nohello = context.getBean("nohello", Hello.class);
System.out.println(nohello.toString());
nohello.helloWord();
}
}
创建了两个对象
这个过程就叫控制反转 :
控制 : 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是由Spring来创建的
反转 : 程序本身不创建对象 , 而变成被动的接收对象 .
依赖注入 : 就是利用set方法来进行注入的.
IOC是一种编程思想,由主动的编程变成被动的接收
可以通过newClassPathXmlApplicationContext去浏览一下底层源码 .
接下来对最初的案例进行一下修改:
<?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="mysqlImpl" class="com.lx.dao.UserDaoMysqlimpl"/>
<bean id="orcleImpl" class="com.lx.dao.UserDaoOrcleimpl" />
<bean id="userImpl" class="com.lx.dao.UserDaoImpl"/>
<bean id="mysql" class="com.lx.service.UserServiceimpl">
<property name="userDao" ref="mysqlImpl" />
</bean>
<bean id="orcle" class="com.lx.service.UserServiceimpl">
<property name="userDao" ref="orcleImpl"/>
</bean>
<bean id="moren" class="com.lx.service.UserServiceimpl">
<property name="userDao" ref="userImpl"/>
</bean>
<!--
ref : 引用Spring容器中创建好的对象
value : 具体的值,基本数据类型!
-->
</beans>
@Test
public void test3(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserServiceimpl moren = context.getBean("moren", UserServiceimpl.class);
moren.getUser();
System.out.println("-----------------");
UserServiceimpl mysql = context.getBean("mysql", UserServiceimpl.class);
mysql.getUser();
System.out.println("------------");
UserDaoMysqlimpl mysqlImpl = context.getBean("mysqlImpl", UserDaoMysqlimpl.class);
mysqlImpl.getUser();
}
设置的6个bean里,其中前三个,可以让用户直接创建dao层的对象,
后三个,依然是先创建了service层的对象,在service使用set注入的方式,将在spring配置好的引用的对象注入进去,这样用户可以不用直接创建dao层的对象也能实现