1、理解
1.1 以前写代码
我们一般都是先写接口,再写实现类,需求改变了我我们再修改接口对应的实现类。
如我们现在有以下:
UserDao有两个实现类。
public interface UserDao {
void getUser();
}
public class UserDaoMysqlImpl implements UserDao{
public void getUser() {
System.out.println("mysql的实现");
}
}
public class UserDaoOracleImpl implements UserDao{
public void getUser() {
System.out.println("Oracle的实现");
}
}
此时我们在业务层是这么使用的
public class UserServiceImpl implements UserService{
UserDao userDao = new UserDaoMysqlImpl();
public void getUser() {
userDao.getUser();
}
}
测试:
public class MyTest {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
userService.getUser();
}
}
结果为
mysql的实现
我们需求改变为Oracle,我们需要去service的实现类中修改我们实现的接口
public class UserServiceImpl implements UserService{
UserDao userDao = new UserDaoOracleImpl();
public void getUser() {
userDao.getUser();
}
}
结果为
Oracle的实现
这并不符合我们的开闭原则,我们需求改变了需要修改源代码,体验不好。
1.2 改良!
相较于上面的代码,我们给userServiceImpl中的UserDao接口加上了Set方法
public class UserServiceImpl implements UserService{
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void getUser() {
userDao.getUser();
}
}
在测试类中,手动给UserDao赋值,结果与我们之前的一样
public class MyTest {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDao(new UserDaoMysqlImpl());
userService.getUser();
}
}
1.3 理解
这两个的结果虽然一样,但在思想上却发生了巨大的变化,测试类是我们的用户界面
在第一个例子中,用户需要改需求必须要去改UserServiceImpl中UserDao的实现类,也就是说具体实现哪个需求是UserServiceImpl说了算
在第二个例子中,我们用户只需要在使用是给UserDao以set的方式注入,UserServiceImpl无需改变任何代码,也就是说,此时需求是用户说了算
ioc控制反转,将实现的控制权交给用户去自定义
当然这样的理解是比较粗糙的,我们看一下在spring中如何实现了ioc原理
2、spring中的ioc
2.1 我们原有的代码不用动,引入spring依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.8</version>
</dependency>
用spring-webmvc的原因是,它可以帮助我们自动导入其他spring的东西
2.2 根据官网文档,我们需要创建一个beans.xml(自己命名的)文件来放入我们的bean
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="mysqlImpl" class="cn.butcher.dao.UserDaoMysqlImpl"/>
<bean id="oracleImpl" class="cn.butcher.dao.UserDaoOracleImpl"/>
<bean id="userServiceImpl" class="cn.butcher.service.UserServiceImpl">
<property name="userDao" ref="mysqlImpl"/>
</bean>
</beans>
此时我们在测试类中测试
public class MyTest {
public static void main(String[] args) {
// UserServiceImpl userService = new UserServiceImpl();
// userService.setUserDao(new UserDaoMysqlImpl());
// userService.getUser();
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserServiceImpl userServiceImpl = (UserServiceImpl) context.getBean("userServiceImpl");
userServiceImpl.getUser();
}
}
结果是我们所期待的,此时我们改变需求,只需要在xml里面配置以下就可以了,牛
<bean id="userServiceImpl" class="cn.butcher.service.UserServiceImpl">
<property name="userDao" ref="oracleImpl"/>
</bean>
重新运行测试类
3、再理解,使用spring托管实体类
创建User类
public class User {
private String username ;
private String password;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
在我们的beans.xml中方注册
<bean id="user" class="cn.butcher.pojo.User">
<property name="username" value="butcher"/>
<property name="password" value="butcher123"/>
</bean>
此时我们来测试
public class MyTest2 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = (User) context.getBean("user");
System.out.println(user.toString());
}
}
我们还可以以构造的形式给user注入值
<bean id="user" class="cn.butcher.pojo.User">
<constructor-arg name="username" value="butcher2"/>
<constructor-arg name="password" value="butcher666"/>
</bean>
再重新跑一下测试
总结
- spring创建我们的bean默认是以无参构造创建的,如果没有无参构造,必须在标签中使用constructor-arg给bean注值
- spring注入值得方式(property )是通过set方法注入的,如果我们没有set方法,spring就无法帮我们注入值。