Spring的IOC思想
1.IOC:控制反转
IOC 是指在程序开发中,实例的创建不在由调用者管理,而是由Spring容器创建。 容器会控制对象之间的关系,而不是由程序代码直接控制。 因此控制权由程序代码转移到了Spring容器中。 控制权发生了反转,这就是Spring的IOC思想。
准备工作:修改pom文件
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.15.RELEASE</version>
</dependency>
刷新maven即可添加。
2.使用bean标签:
先创建一个preson类
package com.lr.spring.po;
public class Person {
//属性
private Integer id;
private String name;
private double sal;
//无参构造方法
public Person (){
System.out.println("创建person对象");
}
}
配置文件
<?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">
<!--
beans是spring中的根标签,在bean标签中配置自己需要的对象
1.bean在spring中相当于java中的对象,需要把该对象对应的类配置到容器中
2.id="":标识,相当于对象名,唯一
3.class="包名.类名(即全限定名)" 包名.类名通过反射创建该类的对象,不能写接口名
-->
<bean id="person1" class="com.lr.spring.po.Person"></bean>
<!-- 把Person类纳入到spring管理中,当程序执行(默认),在spring容器,创建一个Preson类的对象preson1(反射) -->
</beans>
?测试类
package com.lr.spring;
import com.lr.spring.po.Person;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AppTest{
@Test
public void test01(){
BeanFactory factory = new ClassPathXmlApplicationContext("application.xml");
Person person = (Person)factory.getBean("person1");
System.out.println(person);
//单例模式:对象person是唯一的
Person person2 = (Person)factory.getBean("person1");
System.out.println(person2);
}
}
测试结果
3.:单例模式与多例模式
单例模式:singleton
默认值,单例(不管任何人,多少人过来访问,拿到的都是同一个对象)
<bean id="person1" class="com.lr.spring.po.Person" scope="singleton"></bean>
?多例模式:prototype
多例,懒加载(延迟加载),读取配置文件的时候不创建对象,只有调用getBean()方法的时候,才创建对象
<bean id="person1" class="com.lr.spring.po.Person" scope="prototype"></bean>
加入多例模式后,测试结果发生的变化,两个对象地址不一样了
?
4.懒加载
beans是spring中的根标签,在bean标签中配置自己需要的对象
1.bean在spring中相当于java中的对象,需要把该对象对应的类配置到容器中
2.id="":标识,相当于对象名,唯一
3.class="包名.类名(即全限定名)" 包名.类名通过反射创建该类的对象,不能写接口名
-->
<bean id="person1" class="com.lr.spring.po.Person" scope="prototype" lazy-init="default"></bean>
<!-- 把Person类纳入到spring管理中,当程序执行(默认),在spring容器,创建一个Preson类的对象preson1(反射) -->
<!--scope="prototype"/"singleton":控制spring容器创建的对象是单例还是多例
singleton:默认值,单例(不管任何人,多少人过来访问,拿到的都是同一个对象)
prototype:多例,懒加载(延迟加载),读取配置文件的时候不创建对象,只有调用getBean()方法的时候,才创建对象
lazy-init="true"/"default"/"false":主要是针对单例模式的
true:懒加载(延迟加载),只有使用的时候才真正创建该类对象
default/false:不懒加载,读取配置文件时就立刻创建对象,default是默认值
-->
?ioc实例
1.创建User类
package com.lr.spring.po;
import java.io.Serializable;
public class User implements Serializable {
public Integer id;
private String name;
private String password;
public User() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
2.写入配置文件,用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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user1" class="com.lr.spring.po.User"></bean>
<bean id="user2" class="com.lr.spring.po.User"></bean>
<bean id="user3" class="com.lr.spring.po.User"></bean>
</beans>
3.测试程序
测试ApplicationContext()中的几个方法
package com.lr.spring;
import com.lr.spring.po.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AppTest{
@Test
public void test01(){
//ApplicationContext在实际开发中取代了BeanFactory,功能更加枪法,而且有很多其他功能
ApplicationContext factory = new ClassPathXmlApplicationContext("application.xml");
User user1=(User)factory.getBean("user1");
System.out.println(user1);
//getBeanDefinitionCount()可以查配置文件里有多少个对象
int count = factory.getBeanDefinitionCount();
System.out.println("对象的个数:"+count);
//getBeanDefinitionNames():获取对象的名字
String[] names =factory.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
}
//通过程序在初始化的时候,导入Bean配置文件,然后得到Bean实例。
ApplicationContext factory2 =new FileSystemXmlApplicationContext("D:\\code\\spring02\\src\\main\\resources\\application.xml");
User user1 = (User) factory2.getBean("user1");
System.out.println(user1);
添加其他类
添加date类
1.配置文件
注意,这里需要绝对路径,date类在其他包里
<?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="user1" class="com.lr.spring.po.User"></bean>
<bean id="user2" class="com.lr.spring.po.User"></bean>
<bean id="user3" class="com.lr.spring.po.User"></bean>
<bean id="date1" class="java.util.Date"></bean>
</beans>
2.测试程序?
ApplicationContext factory = new ClassPathXmlApplicationContext("application.xml");
Date date1=(Date) factory.getBean("date1");
System.out.println(date1);
?
在User加入多参构造方法,与tostring方法,测试默认调用无参构造方法?
?
工厂模式
如果想调用多参构造方法呢?使用工厂模式:写一个UserFactory类,提供方法
1.静态方法创建对象
package com.lr.spring.factory;
import com.lr.spring.po.User;
public class UserFactory {
//静态方法创建对象(3参构造方法)
public static User getUserStaticInstance(){
System.out.println("通过spring调用工厂中的静态方法创建3参User对象:");
return new User(1111,"龙傲天","1380341");
}
}
2.配置文件
!-- 通过spring调用工厂中的静态方法创建3参User对象 -->
<!-- 静态方法 -->
<bean id="user4" class="com.lr.spring.factory.UserFactory" factory-method="getUserStaticInstance"></bean>
3测试文件?
@Test
public void test02(){
ApplicationContext app=new ClassPathXmlApplicationContext("application.xml");
User user=(User) app.getBean("user4");
System.out.println(user);
}
1.实例方法创建对象?
//实例方法创建对象
public User getUserInstance(){
System.out.println("通过spring调用工厂中的静态方法创建3参User对象");
return new User(2222,"唐三","123456");
}
?2.配置文件
<!-- 使用实例方法 -->
<bean id="factory" class="com.lr.spring.factory.UserFactory"></bean>
<bean id="user5" factory-bean="factory" factory-method="getUserInstance"></bean>
?3测试程序
public void test02(){
ApplicationContext app=new ClassPathXmlApplicationContext("application.xml");
// User user=(User) app.getBean("user4");
// System.out.println(user);
User user=(User) app.getBean("user5");
System.out.println(user);
}
?
4. 补充bean标签属性
init属性(初始化)? ? ? ?destroy属性(销毁)
<bean id="user1" class="com.lr.spring.po.User" init-method="init" destroy-method="destory"></bean>
测试初始化
?测试销毁方法
ps:需要用到实现类,因为ApplicationContext没有close()方法
public void test03(){
ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("application.xml");
// User user=(User) app.getBean("user4");
// System.out.println(user);
User user=(User) app.getBean("user5");
System.out.println(user);
app.close();//关闭Spring容器
}
}
?
?
使用构造方法创建bean对象
两种方法
通过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">
<!--使用构造方法创建bean对象-->
<bean id="user1" class="com.lr.spring.po.User">
<constructor-arg name="id" value="1003"></constructor-arg>
<constructor-arg name="name" value="张三"></constructor-arg>
<constructor-arg name="password" value="123456"></constructor-arg>
</bean>
<bean id="user2" class="com.lr.spring.po.User">
<constructor-arg name="id" index="0" value="1004"></constructor-arg>
<constructor-arg name="name" index="1" value="李四"></constructor-arg>
<constructor-arg name="password" index="2" value="654321"></constructor-arg>
</bean>
</beans>
测试程序
@Test
public void test03(){
ApplicationContext factory = new ClassPathXmlApplicationContext("application2.xml");
User user01=(User) factory.getBean("user1");
System.out.println(user01);
User user02=(User) factory.getBean("user2");
System.out.println(user02);
}
测试结果
两种方法都能创建对象
DI:依赖注入
DI—Dependency Injection,即“依赖注入”
是组件之间依赖关系由容器在运行期决定
我们只需要通过 简单的配置,无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,不需要关心具体的资源来自何处,由谁实现?
?
加入数据访问层dao与业务层service
面向接口编程:减少因为Dao层的改变,对业务层代码的修改.
1.业务逻辑
以前我们常用的业务逻辑
//UserService
package com.lr.spring.service;
public interface UserService {
void addUser();
}
//UserDao
package com.lr.spring.dao;
public interface UserDao {
void addUser();
}
//UserServiceImpl
import com.lr.spring.dao.UserDaoImpl;
public class UserServiceImpl implements UserService {
private UserDaoImpl userDao = new UserDaoImpl();
@Override
public void addUser() {
System.out.println("调用UserDao,插入User对象");
userDao.addUser();
}
}
//UserDaoImpl
package com.lr.spring.dao;
public class UserDaoImpl implements UserDao {
@Override
public void addUser() {
System.out.println("Dao中输入User对象");
}
}
2.人为实现?DI注入
spring可以做到更完美的解耦合,令dao层的改动完全不影响service层,我们需要修改serviceinpl
这个方法就是DI注入
人为实现DI注入代码,有三种方法
第一种:set注入
package com.lr.spring.service;
import com.lr.spring.dao.UserDao;
import com.lr.spring.dao.UserDaoImpl;
public class UserServiceImpl implements UserService {
// private UserDaoImpl userDao = new UserDaoImpl();
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void addUser() {
System.out.println("调用UserDao,插入User对象");
userDao.addUser();
}
//通过set注入
public static void main(String[] args) {
UserServiceImpl userService=new UserServiceImpl();
userService.setUserDao(new UserDaoImpl());
}
}
Spring实现DI注入
第一种set注入
set
注入也叫设值注入是指,通过
setter
方法传入被调用者的实例。这种注入方式简单、直观,因而在
Spring
的依赖注入中大量使用。
1.配置文件
<?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 name="userDao" class="com.lr.spring.dao.UserDaoImpl"></bean>
<bean name="suerService" class="com.lr.spring.service.UserServiceImp
<!-- property标签中的name参数跟set方法名字一一对应,跟属性名无关 -->
<property name="userDao" ref="userDao"></property>
</bean>
</beans>
?ps:property标签中的name参数跟set方法名字一一对应,跟属性名无关?
2.测试程序
@Test
public void test04(){
ApplicationContext factory = new ClassPathXmlApplicationContext("application3.xml");
UserService userService=(UserService) factory.getBean("userService");
userService.addUser();
}
?
第二种:通过构造方法注入?
构造注入是指,在构造调用者实例的同时,完成被调用者的实例化。使用构造器设置依赖关系。
<!-- 构造方法注入 -->
<!-- constructor-arg标签中的name参数跟构造方法中的参数名字名字一一对应,跟属性名无关 -->
<bean name="userService" class="com.lr.spring.service.UserServiceImpl">
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>
?
结果一模一样
ps:constructor-arg标签中的name参数跟构造方法中的参数名字名字一一对应,跟属性名无关
扩展?
新增两个dao实现类,我们使用set注入的方式
package com.lr.spring.dao;
public class UserMySQLDaoImpl implements UserDao {
@Override
public void addUser() {
System.out.println("MySQLDa");
}
}
package com.lr.spring.dao;
public class UserOracleDaoImpl implements UserDao {
@Override
public void addUser() {
System.out.println("OracleDao");
}
}
配置文件?
<bean name="userDao" class="com.lr.spring.dao.UserDaoImpl"></bean>
<bean name="userMySQLDao" class="com.lr.spring.dao.UserMySQLDaoImpl"></bean>
<bean name="userOracleDao" class="com.lr.spring.dao.UserOracleDaoImpl"></bean>
<bean name="userService" class="com.lr.spring.service.UserServiceImpl">
<property name="userDao" ref="userMySQLDao"></property>
</bean>
?
如果我们的数据库换成MySQL只需修改配置文件property标签ref属性值为userMySQLDao即可。
第三种:自动注入?
对于引用类型属性的注入,也可不在配置文件中显示的注入。可以通过为标签
设置
autowire
属性值,为引用类型属性进行隐式自动注入(默认是不自动注入引用类型属 性)。根据
自动注入判断标准的不同,可以分为两种:
byName
:根据名称自动注入,跟set方法中的方法名对应
byType
: 根据类型自动注入,跟属性的类型对应(只有一个的时候使用)
?
?
|