如下图,展示了Spring的大体框架。本文将详细介绍Spring框架中的IOC(控制反转)机制及其应用。
依赖注入就是给对象赋值,依赖注入是通过容器为对象动态赋值的一种设计模式
IOC(控制反转)将对象的创建与管理交由Spring框架处理,其底层机制依赖于反射技术。
AOP(面向切面编程)无需改动原有代码即可增强功能,提升系统的模块化和可维护性,其底层机制依赖于代理技术。
引言
下图展示了代码的文件夹结构截图,其中Animal和User是类,Config在下文的纯注解方案里使用,ATest和UserTest是两个测试类分别测试Animal和User,Spring.xml文件中包含相关XML配置语句。
下图展示了在IntelliJ IDEA中创建Spring.xml文件的简单步骤:
基于xml配置的形式
创建对象
在Spring.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">
<!--IOC管理bean-->
<!--id:类的唯一标识符 class:类的全路径名-->
<bean id="user" class="com.qcby.entity.User"/>
<bean id="animal" class="com.qcby.entity.Animal"/>
<!--Class clazz=Class.forName("全类名")-->
<!--Spring.xml文件是Spring框架的配置信息-->
</beans>
在UserTest文件:
package com.qcby;
import com.qcby.entity.Animal;
import com.qcby.entity.User;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserTest {
//传统创建对象方法
@Test
public void test(){
User user=new User();
user.run();
}
//Spring方式
@Test
public void test1(){
ApplicationContext ac=new ClassPathXmlApplicationContext("Spring.xml");
User user= (User) ac.getBean("user");
user.run();
}
@Test
public void test2(){
ApplicationContext ac=new ClassPathXmlApplicationContext("Spring.xml");
Animal animal= (Animal) ac.getBean("animal");
animal.flay();
}
}
在Spring框架中,对象的创建可以通过两种方式实现:使用BeanFactory
和ApplicationContext
。
BeanFactory:采用延迟加载机制,即在加载配置文件时不会立即创建对象,只有在调用
getBean()
方法获取对象时才会进行实例化。例如:BeanFactory bf = new ClassPathXmlApplicationContext("Spring.xml"); Animal animalBF = (Animal) bf.getBean("animal");
这种方式适合资源有限的环境,但首次获取对象时可能会有性能开销。
ApplicationContext:在加载配置文件时立即创建并初始化所有单例对象,无需等待
getBean()
调用。例如:ApplicationContext ac = new ClassPathXmlApplicationContext("Spring.xml"); Animal animal = (Animal) ac.getBean("animal");
这种方式在应用启动时完成对象的创建,适合大多数场景,能够提高运行时性能。
总结来说,BeanFactory
延迟加载,适合资源敏感场景;ApplicationContext
预加载,适合需要高性能的应用。
依赖注入
依赖注入(赋值)的实现方式主要有两种:
通过setter和getter方法:在类中定义setter方法,Spring容器调用该方法为属性赋值。
通过构造方法:在类中定义带参数的构造方法,Spring容器通过构造方法直接注入依赖对象。
通过set和get
Spring.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">
<!-- IOC 管理 bean -->
<bean id="user" class="com.qcby.entity.User">
<property name="age" value="18"/>
<property name="name" value="Lee"/>
<property name="animal" ref="animal"/>
</bean>
<bean id="animal" class="com.qcby.entity.Animal">
<property name="strs">
<array>
<value>ZhangSan</value>
<value>LiSi</value>
<value>WangWu</value>
<value>ZhaoLiu</value>
</array>
</property>
<property name="list">
<list>
<value>XiaoBai</value>
<value>XiaoHong</value>
<value>XiaoLv</value>
</list>
</property>
<property name="map">
<map>
<entry key="1" value="aa"/>
<entry key="2" value="bb"/>
<entry key="3" value="cc"/>
</map>
</property>
</bean>
</beans>
ATest:
package com.qcby;
import com.qcby.entity.Animal;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ATest {
@Test
public void a(){
ApplicationContext ac=new ClassPathXmlApplicationContext("Spring.xml");
Animal animal= (Animal) ac.getBean("animal");
System.out.println(animal.toString());
}
}
通过构造器
Spring.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">
<!-- IOC 管理 bean -->
<bean id="user" class="com.qcby.entity.User">
<constructor-arg name="age" value="18"/>
<constructor-arg name="name" value="Lee"/>
<constructor-arg name="animal" ref="animal"/>
</bean>
<bean id="animal" class="com.qcby.entity.Animal">
<constructor-arg name="strs">
<array>
<value>ZhangSan</value>
<value>LiSi</value>
<value>WangWu</value>
<value>ZhaoLiu</value>
</array>
</constructor-arg>
<constructor-arg name="list">
<list>
<value>XiaoBai</value>
<value>XiaoHong</value>
<value>XiaoLv</value>
</list>
</constructor-arg>
<constructor-arg name="map">
<map>
<entry key="1" value="aa"/>
<entry key="2" value="bb"/>
<entry key="3" value="cc"/>
</map>
</constructor-arg>
</bean>
</beans>
基于注解的形式
Spring框架为Bean管理提供了多种注解,用于标识不同层次的组件并创建Bean实例:
@Component:通用的注解,用于标注普通的类,将其作为Bean注册到Spring容器中。
@Controller:专门用于表现层(如MVC模式中的控制器),标识该类为Web层的组件。
@Service:用于业务逻辑层,标识该类包含业务逻辑,是服务层的组件。
@Repository:用于持久层,通常标注在数据访问对象(DAO)类上,标识该类负责数据库操作。
虽然这四个注解的功能相同,都可以创建Bean实例,但通过不同的注解可以更清晰地划分代码层次,增强代码的可读性和可维护性。在实际开发中,应根据类的职责选择合适的注解。
创建对象
Spring.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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启注解扫描,扫描 com.qcby.entity 包中的所有类 -->
<context:component-scan base-package="com.qcby.entity" />
</beans>
User:
package com.qcby.entity;
import org.springframework.stereotype.Component;
@Component
public class User {
public void run(){
System.out.println("human run fast");
}
}
UserTest:
package com.qcby;
import com.qcby.entity.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserTest {
@Test
public void test1(){
ApplicationContext ac=new ClassPathXmlApplicationContext("Spring.xml");
User user= (User) ac.getBean("user");
user.run();
}
}
实现注入
@Value 用于注入普通类型(String,int,double等类型)
@Autowired 默认按类型进行自动装配(引用类型)
@Qualifier 不能单独使用必须和@Autowired一起使用,强制使用名称注入
@Resource Java提供的注解,也被支持。使用name属性,按名称注入
纯注解方案
这种方法不需要xml
Config.java:
package com.qcby.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(value = "com.qcby.entity")
public class Config {
}
UserTest:
package com.qcby;
import com.qcby.config.Config;
import com.qcby.entity.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserTest {
@Test
public void test1(){
ApplicationContext ac=new AnnotationConfigApplicationContext(Config.class);
User user= (User) ac.getBean("user");
user.run();
}
}