笔记
1.传统的业务实现
/** * dao接口 */ public interface UserDao { void getUser(); } /** * 实现类1 */ public class UserDaoImpl implements UserDao{ public void getUser() { System.out.println("getUser方法"); } } /** * 业务层接口 */ public interface UserService { void getUser(); } /** * 业务实现类 */ public class UserServiceImpl implements UserService { private UserDao userDao = new UserDaoImpl(); public void getUser() { userDao.getUser(); } } /** * 测试类 */ @Test public void test(){ UserServiceImpl userService = new UserServiceImpl(); userService.setUserDao(new UserOracleImpl()); userService.getUser(); }
输出:
getUser方法
当需要修改业务更换dao接口的时候,我们需要修改源代码
于是我们
1.添加一个dao实现类
2.修改业务实现类
3.其他不变
/** * 实现类2 */ public class UserDaoMysqlImpl implements UserDao { public void getUser() { System.out.println("mysql的实现"); } } /** * 业务实现类 */ public class UserServiceImpl implements UserService { private UserDao userDao = new UserDaoMysqlImpl(); public void getUser() { userDao.getUser(); } }
输出:
mysql的实现
如果业务需求更换,需要再换加一种dao实现,那么我们也是一样的操作
/** * 实现类3 */ public class UserOracleImpl implements UserDao{ public void getUser() { System.out.println("Oracle的实现"); } } public class UserServiceImpl implements UserService { private UserDao userDao = new UserOracleImpl(); public void getUser() { userDao.getUser(); } } 输出: Oracle的实现
一种好的解决方式是:
/** * 业务实现类 */ public class UserServiceImpl implements UserService { private UserDao userDao; /** 手动使用set注入的方式,实现可用动态更改dao实现类 */ public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void getUser() { userDao.getUser(); } } @Test public void test(){ UserServiceImpl userService = new UserServiceImpl(); userService.setUserDao(new UserDaoImpl()); // userService.setUserDao(new UserDaoMysqlImpl()); // userService.setUserDao(new UserOracleImpl()); userService.getUser(); }
组合对象,通过set方法,当我们需要什么实现的时候,再设置(通过组合解耦)
spring如何解耦
/** * dao接口 */ public interface UserDao { void getUser(); } /** * 实现类1 */ public class UserDaoImpl implements UserDao{ public void getUser() { System.out.println("getUser方法"); } } /** * 实现类2 */ public class UserDaoMysqlImpl implements UserDao { public void getUser() { System.out.println("mysql的实现"); } } /** * 实现类3 */ public class UserOracleImpl implements UserDao{ public void getUser() { System.out.println("Oracle的实现"); } } /** * 业务层接口 */ public interface UserService { void getUser(); } /** * 业务实现类 */ public class UserServiceImpl implements UserService { private UserDao userDao; /** 手动使用set注入的方式,实现可用动态更改dao实现类 */ public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void getUser() { userDao.getUser(); } }
resources/application.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来创建bean--> <bean id="userDao" class="gg.dao.UserDaoImpl"/> <bean id="userDaoMysql" class="gg.dao.UserDaoMysqlImpl"/> <bean id="userOracle" class="gg.dao.UserOracleImpl"/> <bean id="userService" class="gg.service.UserServiceImpl"> <!-- <property name="userDao" ref="userDaoMysql"/>--> <property name="userDao" ref="userOracle"/> <!-- <property name="userDao" ref="userDao"/>--> </bean> </beans> @Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); UserServiceImpl userService = context.getBean("userService", UserServiceImpl.class); userService.getUser(); } 输出: Oracle的实现
通过spring管理bean,我们只需要在bean中配置不同的dao实现就可以轻轻松松应对多变的需求
spring使用解析
导入依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.10.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency>
public class User { private String name; public User() { System.out.println("使用了无参构造方法"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public void show(){ System.out.println("name = " + name); } } <?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来创建bean 默认使用了无参构造方法来创建对象 相当于执行了 public User() { System.out.println("使用了无参构造方法"); } --> <bean id="user" class="com.gg.entity.User"> <property name="name" value="小明"/> </bean> </beans> @Test public void test(){ // 创建对象调用无参构造方法 User user = new User(); // 没有调用setName方法,输出 name = null user.show(); ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); User user1 = context.getBean("user", User.class); // spring的xml文件中管理注入了name属性,输出 name = 小明 user1.show(); } 输出: 使用了无参构造方法 name = null 使用了无参构造方法 name = 小明
可以看到,用spring管理的bean对象其实是调用了对象的无参构造方法
<property name="name" value="小明"/>
输出中,name = 小明 其实也是调用了User类中的setName方法
<!-- 使用spring来创建bean 相当于:User user = new User() --> <bean id="user" class="com.gg.entity.User"> <!-- property采用的是set注入,实体去掉了setName就会报红 相当于:user.setName("小明") --> <property name="name" value="小明"/> </bean>
怎么证明呢?
我们把setName方法注释掉
编辑器提示我们创建一个setName方法,所以
点击红框idea在User类中添加了一个setName方法(但是需要我们实现)
所以的确证明spring中管理注册bean的property就是通过setXXX方法实现的
向spring再进一步
1.使用构造器下标方式注入属性
public class User { private String name; // 添加一个字段,理解参数顺序的bean创建 private int age; /** * 干掉无参构造方法,创建一个有参数的构造方法 * @return */ public User() { System.out.println("使用了无参构造方法"); } public User(String name,int age){ this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void show(){ System.out.println("name = " + name); } } <!--1.使用构造器下标方式注入--> <bean id="user" class="com.gg.entity.User"> <!-- public User(String name,int age){ 索引从0开始 --> <constructor-arg index="0" value="小明1"/> <constructor-arg index="1" value="21"/> </bean> @Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); User user1 = context.getBean("user", User.class); // 通过constructor-arg方法index注入 System.out.println("user1.getName() = " + user1.getName()); System.out.println("user1.getAge() = " + user1.getAge()); } 输出: user1.getName() = 小明1 user1.getAge() = 21
2.使用参数类型注入属性
public User(String name,int age){ this.name = name; this.age = age; } <!--2.使用参数类型注入--> <bean id="user" class="com.gg.entity.User"> <constructor-arg type="java.lang.String" value="小明2"/> <constructor-arg type="int" value="22"/> </bean>
输出: user1.getName() = 小明2 user1.getAge() = 22
3.使用参数名设置
<!--3.使用参数名来设置--> <bean id="user" class="com.gg.entity.User"> <constructor-arg name="name" value="小明3"/> <constructor-arg name="age" value="23"/> </bean> 输出: user1.getName() = 小明3 user1.getAge() = 23
以上笔记内容来源B站狂神说的视频前6节.