猿创征文 | Spring框架管理对象(IOC详解)
Posted 爱吃豆的土豆
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了猿创征文 | Spring框架管理对象(IOC详解)相关的知识,希望对你有一定的参考价值。
目录
1,管理对象(IOC详解)
-
Spring框架是企业使用最多的框架,没有之一。
-
Spring是一站式框架,也就是Spring可以整合其他框架。
-
Spring IoC:对象工厂及依赖注入。
-
Spring AOP:面向切面编程技术,Spring事务管理的基础。
-
Spring Transaction management:Spring事务管理。
-
Spring Web MVC:后面单独学习。
-
1.1 :什么是IOC
-
IoC 是 Inversion of Control 的缩写,即“控制反转”。
-
控制反转:将创建对象的权利,由自己(new)反转给spring。
-
图解1:未使用IoC
-
图解2:使用IoC
-
IoC作用:
-
统一管理对象
-
解决对象之间的耦合
-
之前使用,类之间存在耦合
-
-
解决程序耦合
-
servlet类中,只用了service接口,表示web层和service层解耦。
-
service实现类中,只用了dao的接口,表示service层和dao层解耦。
好处: 可以实现解耦, 让类和类之间的耦合度降低, 将对象的创建权交给Spring管理
1.2:Bean创建
-
在spring 容器中管理的对象,统称为
bean
。例如:UserDao、UserService 等
1.2.1:Bean相关注解
注解 | 描述 |
---|---|
@Component | 将修饰的资源交予spring管理。 value属性:为资源命名(唯一标识) |
@Controller | 衍生注解,与@Component作用和属性相同。特用于修饰==表示层==的资源。 |
@Service | 衍生注解,与@Component作用和属性相同。特用于修饰==业务逻辑层==的资源。 |
@Repository | 衍生注解,与@Component作用和属性相同。特用于修饰==数据访问层==的资源。 |
1.3:依赖注入(DI)
1.3.1:什么是DI
依赖注入(Dependency Injection,DI)Spring 容器在创建被调用者的实例时,会自动将调用者需要的对象实例注入给调用者。
注解 | 描述 | 修饰位置 |
---|---|---|
@Resource(name=”…”) | 按照指定名称注入对象 | 字段、setter方法 |
@ Resource | 按照类型注入对象 | 字段、setter方法 |
@Value | 注入简单值 | 字段、setter方法、参数 |
@PropertySource | 加载properties配置文件 | 类 |
1.3.2:按照名称注入
public class 类名
@Resource(name="名称")
private 类型 变量;
字段注入
@Resource(name = "studentService4")
private StudentService studentService;
setter方法注入
private StudentService studentService;
@Resource(name = "studentService4")
public void setStudentService(StudentService studentService)
this.studentService = studentService;
1.3.3:按照类型注入
public class 类名
@Resource
private 类型 变量;
1.3.4:注入简单数据:@Value
-
简单数据:基本数据类型、字符串等。
-
需要:定义User对象,给User对象注入数据
@Value 可以给成员变量注入、也可以给属性注入(getter/setter)
-
步骤
-
步骤1:目标类,User,进行普通数据注入
-
步骤2:配置类
-
步骤3:测试类
-
步骤1:目标类,User,进行普通数据注入
@Component
public class User
@Value("jack")
private String username;
@Value("18")
private Integer age;
//....
步骤2:配置类
@Configuration
@ComponentScan(basePackages = "com.czxy.demo05_di_value.domain")
public class Demo05Configuration
步骤3:测试类
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = Demo05Configuration.class)
public class TestDemo05
@Resource
private User user;
@Test
public void testDemo5()
System.out.println(user);
1.3.5:properies数据注入
-
需求:读取数据库配置信息
-
步骤:
-
步骤1:编写demo07.properties文件
-
步骤2:编写配置类,读取properties内容。@Value修饰setter
-
步骤3:测试类
-
编写properties文件,key=value
#key=value
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db2
jdbc.username=root
jdbc.password=1234
使用@PropertySource("classpath:properties文件")加载properties文件,使用@Value("$key")进行注入
测试类
1.4:@Bean注入第三方类
-
在实际开发中,有很多第三方提供类(jar包里),需要在spring中使用。
-
Spring提供@Bean注解,整合第三方类。
注解 | 描述 |
---|---|
@Bean | 将第三方对象,添加到spring容器中,方法名为默认名。 |
@Bean(name = "") | 按照指定名称,将第三方对象,添加到spring容器中。 |
1.4.1:按照类型
-
需要:假设UserDao是第三方(不能添加注解),需要使用UserDao
-
步骤:
-
步骤1:模拟类
-
步骤2:配置类
-
步骤3:测试类
-
-
模拟类
-
配置类
配置类
-
@RunWith(SpringRunner.class) @ContextConfiguration(classes = Demo08Configuration.class) public class TestDemo08 @Resource private UserDao userDao; @Test public void testDemo07() // UserDao userDao = new UserDao(); userDao.selectAll();
1.4.2:按照名称
-
需求:定义一个UserDao接口,编写2个实现类A、B,分别按照名称进行注入
-
步骤:
-
模拟数据类
-
接口
-
实现类A
-
实现类B
-
-
配置类,创建2个实现类,并进行不同的命名
-
测试类,依次注入不同命名的实现类
-
-
实现
-
配置类
-
@Configuration public class Demo09Configuration @Bean(name="userDaoA") public UserDao createUserDaoA() return new UserDaoImplA(); @Bean(name="userDaoB") public UserDao createUserDaoB() return new UserDaoImplB();
测试类
-
@RunWith(SpringRunner.class) @ContextConfiguration(classes = Demo09Configuration.class) public class TestDemo09 @Resource(name="userDaoA") private UserDao userDaoA; @Resource(name="userDaoB") private UserDao userDaoB; @Test public void testDemo07() userDaoA.selectAll(); userDaoB.selectAll();
-
1.4.3:参数类型:引入数据
-
需求:service、dao 都是第三方
-
@Bean 修饰的方法,如果有参数,将自动注入。
@Bean
public 返回值 方法名(参数类型 参数名) //主动注入参数对象
-
步骤:
-
模拟类
-
UserDao
-
UserService
-
-
配置类
-
编写方法,createUserDao
-
编写方法,createUserService( UserDao userDao )
-
-
测试类
-
-
实现
-
模拟类:dao实现类没有注解
-
public interface StudentDao
public void selectAll();
public class StudentDaoImpl implements StudentDao
@Override
public void selectAll()
System.out.println("demo10 student dao ");
模拟类:service,没有注解
public interface StudentService
public void selectAll();
public class StudentServiceImpl implements StudentService
private StudentDao studentDao;
public void setStudentDao(StudentDao studentDao)
this.studentDao = studentDao;
@Override
public void selectAll()
System.out.println("demo10 student service");
studentDao.selectAll();
配置类
@Configuration
@ComponentScan(basePackages = "com.czxy.demo10_bean_param")
public class Demo10Configuration
@Bean
public StudentDao studentDao()
return new StudentDaoImpl();
@Bean
public StudentService studentService10(StudentDao studentDao)
StudentServiceImpl studentService = new StudentServiceImpl();
studentService.setStudentDao(studentDao);
return studentService;
测试类
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = Demo10Configuration.class)
public class TestDemo10
@Resource(name = "studentService10")
private StudentService studentService;
@Test
public void testDemo()
studentService.selectAll();
1.4.4:参数类型:简单数据
properties配置文件
配置类
测试类
1.5:Bean作用域
1.5.1:概述
-
bean作用域:一个对象的使用范围。
-
通过@Scope可以设置Bean的作用域
注解 | 取值 | |
---|---|---|
@Scope | singleton | 默认值,单例的。整个spring容器只有一个 |
prototype | 多例的。每获得一次创建一份 |
-
需求:编写UserDao,获得对象,注入2次。
1.5.2:单例
dao,确定作用域方式
@Repository
@Scope("singleton")
public class UserDao
配置类
测试类,注入2次,打印结果一样的。
1.5.3:多例
修改单例代码
1.5.4:常量
1.6:生命周期
1.6.1:什么是生命周期
-
生命周期:指Spring创建Bean到销毁Bean的整个过程。
-
spring bean 完整生命周期参数
-
在实际开发中,最常用的是bean
初始化
和销毁
。
1.6.2:生命周期详解
-
完整示意图
实例:(⑧、⑬为XML配置内容)
-
步骤1:创建后处理bean
-
@Component public class MyBeanPostProcessor implements BeanPostProcessor @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException if("dog".equalsIgnoreCase(beanName)) System.out.println("5. BeanPostProcessor#before --> " + beanName); return bean; @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException if("dog".equalsIgnoreCase(beanName)) System.out.println("9. BeanPostProcessor#after --> " + beanName); return bean;
步骤2:编写目标类Dog
-
@Component //@Scope("prototype") public class Dog implements BeanNameAware, BeanFactoryAware, InitializingBean, DisposableBean public Dog() System.out.println("1. 初始化"); @Value("旺财") public void setName(String name) System.out.println("2. properties --> " + name); @Override public void setBeanName(String s) System.out.println("3. BeanNameAware#setBeanName --> " + s); @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException System.out.println("4. BeanFactoryAware#beanFactory "); @PostConstruct //初始化 public void init() System.out.println("6. 小狗 出生了"); @Override public void afterPropertiesSet() throws Exception System.out.println("7. InitializingBean#afterPropertiesSet"); public void eat() System.out.println("10. 正在吃..."); @PreDestroy //销毁 public void DogDestroy() System.out.println("11. 小狗 挂了"); @Override public void destroy() throws Exception System.out.println("12. DisposableBean#destroy");
步骤3:配置类
-
@Configuration @ComponentScan(basePackages = "com.czxy.demo13_lifecycle.domain","com.czxy.demo13_lifecycle.processor") public class Demo13Configuration
步骤4:测试类
-
@RunWith(SpringRunner.class) @ContextConfiguration(classes = Demo13Configuration.class) public class TestDemo13 @Resource private Dog dog; @Test public void testDemo13() dog.eat();
1.6.3:方式一:详解-初始化&销毁
-
需求:
-
编写目标类Dog,并执行eat方法打印
正在吃...
-
在eat()前后分别执行初始化
小狗 出生了
、销毁小狗 挂了
-
-
目标类:需要完成初始化、销毁功能的类
-
@PostConstruct 用于修饰==初始化==方法。
-
@PreDestroy 用于修饰==销毁==方法。
-
配置类:
测试类:
1.6.4:方式二:第三方@Bean
-
需求:
-
使用@Bean配置目标类Dog的初始化和销毁
-
-
目录类(假设Dog由第三方jar提供,没有源码,不允许使用注解
@Component
)
配置类,使用@Bean注册第三方对象,通过 initMethod 和 destroyMethod 两个属性设置初始化和销毁
测试类
1.6.5:生命周期函数有什么用吗?
释放资源:
public class 类名
@Bean(destroyMethod="close")
public DataSource datasource()
return new DruidDataSource();
Spring框架学习02——Spring IOC 详解
1、Spring IOC的基本概念
IOC(Inverse of Control)反转控制的概念,就是将原本在程序中手动创建对象的控制权,交由Spring框架管理。当某个Java对象(调用者)需要调用另一个Java对象(被调用者)时,在传统编程模式下,调用者通常会采用“new 被调用者”的代码方式来创建对象。这种方式会增加调用者与被调用者之间的耦合性,不利于后期代码的升级与维护。
当Spring框架出现后,对象的实例不再由调用者来创建,而是由Spring容器来创建。Spring容器会负责控制程序之间的关系,而不是由调用者的程序代码直接控制。这样,控制权由调用者转移到Spring容器,控制权发生了反转,这就是Spring的控制反转。
2、Spring IOC容器
实现控制反转的是Spring IOC容器,Spring IOC容器的设计主要是基于Bean Factory和ApplicationContext两个接口。
2.1、BeanFactory接口
BeanFactory由org.springframework.beans.factory.BeanFactory接口定义,它提供了完整的IOC服务支持,是一个管理Bean的工厂,主要负责初始化各种Bean。
BeanFactory接口最常用的实现类是org.springframework.beans.factory.xml.XMLBeanFactory,该类会根据XML配置文件中的定义来装配Bean。
BeanFactory实例创建代码如下:
@Test public void demo(){ FileSystemResource file = new FileSystemResource("C:\\demo\\applicationContext.xml"); BeanFactory beanFactory = new XmlBeanFactory(file); TestDao testDao = (TestDao) beanFactory.getBean("testDao"); testDao.sayHello(); }
由于使用BeanFactory实例加载Spring配置文件在实际开发中并不多见,所以对于该接口仅了解即可。
2.2、ApplicationContext接口
ApplicationContext是BeanFactory的子接口,也称为应用上下文,由org.springframework.context.ApplicationContext接口定义。ApplicationContext接口除了包含BeanFactory的所有功能以外,还添加了对国际化、资源访问、事件传播等内容的支持。
创建ApplicationContext接口实例通常有以下3中方法:
- 通过ClassPathXmlApplicationContext创建
- 通过FileSystemXmlApplicationContext创建
- 通过Web服务器实例化ApplicationContext容器
下面对这3种方法的代码做演示:
(1)ClassPathXmlApplicationContext
使用ClassPathXmlApplicationContext将从类路径目录(src根目录)中寻找指定的XML配置文件,代码示例:
@Test public void demo(){ //初始化Spring容器ApplicationContext,加载配置文件 ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml"); //通过容器获取testDao实例 TestDao testDao = (TestDao) application.getBean("testDao"); testDao.sayHello(); }
(2)FileSystemXmlApplicationContext
使用FileSystemXmlApplicationContext将从指定文件的绝对路径中寻找XML配置文件,找到并装载完成ApplicationContext的实例化工作,代码示例:
@Test public void demo(){ ApplicationContext application = new FileSystemXmlApplicationContext("C:\\demo\\applicationContext.xml"); TestDao testDao = (TestDao) application.getBean("testDao"); testDao.sayHello(); }
(3)使用Web服务器实例化
通过Web服务器实例化ApplicationContext容器,一般使用org.springframework.web.context.ContextLoaderListener的实现方式,需要添加Spring-web依赖,pom.xml配置如下:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.0.2.RELEASE</version> </dependency>
在web.xml中配置代码如下:
<context-param> <!--加载src目录下的applicationContext.xml文件--> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!--指定以ContextLoaderListener方式启动Spring容器--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
通过web.xml配置,web容器会自动加载context-param中的配置文件初始化ApplicationContext实例,然后就可以在web应用中通过WebApplicationContextUtils.getWebApplicationContext方法获取ApplicationContext的引用,Servlet中的代码如下:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws javax.servlet.ServletException, IOException { ApplicationContext application = WebApplicationContextUtils.getWebApplicationContext(request.getServletContext()); TestDao testDao = (TestDao) application.getBean("testDao"); testDao.sayHello(); }
3、依赖注入(基于XML方式)
DI (Dependency Injection)依赖注入的概念,在Spring中实现IOC容器的方法是依赖注入,依赖注入的作用是在使用Spring框架创建对象时动态地将其所依赖的对象(属性值)注入Bean组件中。
Spring框架的依赖注入通常有以下几种实现方式:
- 使用构造方法注入
- 使用属性的setter方法注入
- 使用使用P名称空间注入
- 使用SpEL注入
3.1、使用构造方法注入
创建User类
package test; public class User { private String name; private int age; public User(String name,int age){ this.name = name; this.age = age; } @Override public String toString() { return "User{" + "name=‘" + name + ‘‘‘ + ", age=" + age + ‘}‘; } }
在applicationContext.xml文件中配置user实例
<?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="test.User"> <constructor-arg name="name" value="张三"></constructor-arg> <constructor-arg name="age" value="20"></constructor-arg> </bean> </beans>
在测试方法中代码
@Test public void demo(){ //初始化Spring容器ApplicationContext,加载配置文件 ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml"); //通过容器获取实例 User user = (User) application.getBean("user"); System.out.println(user); }
运行结果
3.2、使用属性的setter方法注入
创建Course课程类
package entity; public class Course { private String cname; public String getCname() { return cname; } public void setCname(String cname) { this.cname = cname; } @Override public String toString() { return "Course{" + "cname=‘" + cname + ‘‘‘ + ‘}‘; } }
创建Student学生类
package entity; public class Student { private String name; private int age; private Course course; @Override public String toString() { return "Student{" + "name=‘" + name + ‘‘‘ + ", age=" + age + ", course=" + course + ‘}‘; } //getter和setter方法 }
配置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"> <!--使用set方法注入--> <bean id="course" class="entity.Course"> <property name="cname" value="大学语文"></property> </bean> <bean id="student" class="entity.Student"> <property name="name" value="张三"></property> <property name="age" value="20"></property> <property name="course" ref="course"></property> </bean> </beans>
测试方法
@Test public void demo(){ //初始化Spring容器ApplicationContext,加载配置文件 ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml"); //通过容器获取实例 Student student = (Student) application.getBean("student"); System.out.println(student); }
运行结果
3.3、使用P名称空间注入
创建Course课程类
package entity; public class Course { private String cname; public String getCname() { return cname; } public void setCname(String cname) { this.cname = cname; } @Override public String toString() { return "Course{" + "cname=‘" + cname + ‘‘‘ + ‘}‘; } }
创建Student学生类
package entity; public class Student { private String name; private int age; private Course course; @Override public String toString() { return "Student{" + "name=‘" + name + ‘‘‘ + ", age=" + age + ", course=" + course + ‘}‘; } //getter和setter方法 }
配置applicationContext.xml文件,要在约束里面加入p名称空间的约束
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" 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"> <!--使用p名称空间注入--> <bean id="course" class="entity.Course" p:cname="英语"></bean> <bean id="student" class="entity.Student" p:name="张三" p:age="20" p:course-ref="course"></bean> </beans>
测试方法
@Test public void demo(){ //初始化Spring容器ApplicationContext,加载配置文件 ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml"); //通过容器获取实例 Student student = (Student) application.getBean("student"); System.out.println(student); }
运行结果
3.4、使用SpEL注入
我们可以使用SpEL(Spring expression language)Spring表达式语言,对依赖注入进行简化。
语法:#{表达式},例如 <bean id="" value="#{表达式}">
#{‘hello‘}:使用字符串
#{beanId}:使用另一个bean
#{beanId.content.toUpperCase()}:使用指定名属性,并使用方法
#{T(java.lang.Math).PI}:使用静态字段或方法
创建Course课程类
package entity; public class Course { private String cname; public String getCname() { return cname; } public void setCname(String cname) { this.cname = cname; } @Override public String toString() { return "Course{" + "cname=‘" + cname + ‘‘‘ + ‘}‘; } }
创建Student学生类
package entity; public class Student { private String name; private int age; private Course course; @Override public String toString() { return "Student{" + "name=‘" + name + ‘‘‘ + ", age=" + age + ", course=" + course + ‘}‘; } //getter和setter方法 }
配置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"> <!--使用SpEL方式注入--> <bean id="course" class="entity.Course"> <property name="cname" value="#{‘高数‘}"></property> </bean> <bean id="student" class="entity.Student"> <property name="name" value="#{‘小明‘}"></property> <property name="age" value="#{10}"></property> <property name="course" value="#{course}"></property> </bean> </beans>
测试方法
@Test public void demo(){ //初始化Spring容器ApplicationContext,加载配置文件 ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml"); //通过容器获取实例 Student student = (Student) application.getBean("student"); System.out.println(student); }
运行结果
在使用SpEL时,配置中也可以调用方法,示例代码如下:
创建获取年龄的类
package entity; public class GetAge { public int createAge(){ return 20; } }
配置applicationContext.xml
<!--使用SpEL方式注入--> <bean id="course" class="entity.Course"> <property name="cname" value="#{‘高数‘}"></property> </bean> <bean id="getAge" class="entity.GetAge"></bean> <bean id="student" class="entity.Student"> <property name="name" value="#{‘小明‘}"></property> <property name="age" value="#{getAge.createAge()}"></property> <property name="course" value="#{course}"></property> </bean>
执行测试方法,运行结果如下:
以上是关于猿创征文 | Spring框架管理对象(IOC详解)的主要内容,如果未能解决你的问题,请参考以下文章