IOC(Inversion Of Control),即控制反转,是一种能够指导我们设计出松耦合、高可扩展应用程序的设计思想。
Spring框架提供了IOC容器相关的实现方式,Spring通过IOC容器管理Bean及Bean之间的依赖关系,其实现方式包括如下两种:
类型名 | 说明 |
---|---|
ClassPathXmlApplicationContext | 通过读取类路径下的 XML 格式的配置文件创建 IOC 容器对象 |
FileSystemXmlApplicationContext | 通过文件系统路径读取 XML 格式的配置文件创建 IOC 容器对象 |
创建子模块giser-java-spring6-01,并引入配置文件beans.xml、log4j2.xml,添加如下依赖:
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>6.1.1version>
dependency>
<dependency>
<groupId>org.junit.jupitergroupId>
<artifactId>junit-jupiter-apiartifactId>
<version>5.10.1version>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-coreartifactId>
<version>2.19.0version>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-slf4j2-implartifactId>
<version>2.19.0version>
dependency>
dependencies>
创建实体类:
public class HelloWorld {
public HelloWorld(){
System.out.println("constructor execute...");
}
public void sayHello(){
System.out.println("hello world!");
}
}
beans.xml配置
<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="helloWorld" class="com.giser.spring6.HelloWorld">bean>
beans>
log4j配置:
<configuration>
<loggers>
<root level="DEBUG">
<appender-ref ref="spring6log"/>
<appender-ref ref="RollingFile"/>
<appender-ref ref="log"/>
root>
loggers>
<appenders>
<console name="spring6log" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/>
console>
<File name="log" fileName="d:/spring6_log/test.log" append="false">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
File>
<RollingFile name="RollingFile" fileName="d:/spring6_log/app.log"
filePattern="log/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
<PatternLayout pattern="%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
<SizeBasedTriggeringPolicy size="50MB"/>
<DefaultRolloverStrategy max="20"/>
RollingFile>
appenders>
configuration>
public class HelloWorldTest {
private Logger logger = LoggerFactory.getLogger(HelloWorldTest.class);
@Test
public void testSpringBean() {
// 读取配置信息
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
}
}
// 根据id获取bean
HelloWorld bean1 = (HelloWorld) applicationContext.getBean("helloWorld");
// 根据bean的类型获取bean,此时要求此类型的bean只能存在一个,否则会抛异常
HelloWorld bean2 = applicationContext.getBean(HelloWorld.class);
HelloWorld bean3 = applicationContext.getBean("helloWorld", HelloWorld.class);
实体:
public class User {
private String userName;
private Integer userAge;
// 无参构造函数
// 全参构造函数
// getter setter toString
}
beans-di.xml
<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="com.giser.spring6.entity.User">
<property name="userName" value="张三"/>
<property name="userAge" value="13" />
bean>
beans>
测试
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-di.xml");
User user = applicationContext.getBean("user", User.class);
<bean id="user1" class="com.giser.spring6.entity.User">
<constructor-arg name="userName" value="张三" />
<constructor-arg name="userAge" value="23" />
bean>
测试
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-di.xml");
User user1 = applicationContext.getBean("user1", User.class);
<bean id="user2" class="com.giser.spring6.entity.User">
<property name="userName" value="张三"/>
<property name="userAge" value="13" />
bean>
<bean id="user3" class="com.giser.spring6.entity.User">
<property name="userName">
<null />
property>
<property name="userAge" value="13" />
bean>
<bean id="user4" class="com.giser.spring6.entity.User">
<property name="userName" value="a < b">property>
<property name="userAge" value="13" />
bean>
<bean id="user5" class="com.giser.spring6.entity.User">
<property name="userName">
<value>value>
property>
<property name="userAge" value="13" />
bean>
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-di.xml");
User user2 = applicationContext.getBean("user2", User.class);
User user3 = applicationContext.getBean("user3", User.class);
User user4 = applicationContext.getBean("user4", User.class);
User user5 = applicationContext.getBean("user5", User.class);
logger.info("特殊值处理-字面量赋值:{}", user2);
logger.info("特殊值处理-null值:{}", user3);
logger.info("特殊值处理-xml实体:{}", user4);
logger.info("特殊值处理-CDATA节:{}", user5);
包括三种方式:引入外部bean、使用内部bean、级联属性赋值。
实体:
public class Dept {
private String deptName;
// getter setter toString
}
public class Emp {
private String empName;
private Integer empAge;
private Dept dept;
// getter setter toString
}
xml文件
<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="dept" class="com.giser.spring6.iocpojo.Dept">
<property name="deptName" value="产品研发部" />
bean>
<bean id="emp1" class="com.giser.spring6.iocpojo.Emp">
<property name="empName" value="小明" />
<property name="empAge" value="32" />
<property name="dept" ref="dept" />
bean>
<bean id="emp2" class="com.giser.spring6.iocpojo.Emp">
<property name="empName" value="小明" />
<property name="empAge" value="32" />
<property name="dept" >
<bean class="com.giser.spring6.iocpojo.Dept">
<property name="deptName" value="董事会" />
bean>
property>
bean>
<bean id="dept3" class="com.giser.spring6.iocpojo.Dept">
<property name="deptName" value="产品研发部" />
bean>
<bean id="emp3" class="com.giser.spring6.iocpojo.Emp">
<property name="empName" value="小明" />
<property name="empAge" value="32" />
<property name="dept" ref="dept3" />
<property name="dept.deptName" value="中央办公室" />
bean>
beans>
测试:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-obj-di.xml");
Emp emp = applicationContext.getBean("emp3", Emp.class);
logger.info("对象类型属性赋值:{}", emp);
public class Student {
private String stuName;
private String[] hobbyArr;
// 无参构造函数
// 全参构造函数
// getter setter toString
}
<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="stu" class="com.giser.spring6.iocarray.Student">
<property name="stuName" value="张三" />
<property name="hobbyArr">
<array>
<value>吃饭value>
<value>睡觉value>
<value>敲代码value>
array>
property>
bean>
beans>
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-arr-di.xml");
Student stu = applicationContext.getBean("stu", Student.class);
logger.info("数组类型属性赋值:{}", stu);
public class Cls {
private List<Stu> stuList;
private String clsName;
// 无参构造函数
// 全参构造函数
// getter setter toString
}
public class Stu {
private String stuName;
private List<String> hobbyList;
// 无参构造函数
// 全参构造函数
// getter setter toString
}
<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="stu" class="com.giser.spring6.ioclist.Stu">
<property name="stuName" value="张三" />
<property name="hobbyList">
<list>
<value>吃饭value>
<value>睡觉value>
<value>敲代码value>
list>
property>
bean>
<bean id="stu2" class="com.giser.spring6.ioclist.Stu">
<property name="stuName" value="李四" />
<property name="hobbyList">
<list>
<value>烧烤value>
<value>炸鸡value>
<value>胡辣汤value>
list>
property>
bean>
<bean id="cls" class="com.giser.spring6.ioclist.Cls">
<property name="clsName" value="中一班" />
<property name="stuList">
<list>
<ref bean="stu" />
<ref bean="stu2" />
list>
property>
bean>
beans>
private Logger logger = LoggerFactory.getLogger(SpringListDITest.class);
@Test
public void testSpecialVal(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-list-di.xml");
Stu stu = applicationContext.getBean("stu", Stu.class);
logger.info("List集合类型属性赋值:{}", stu);
}
@Test
public void testSpecialVal2(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-list-di.xml");
Cls cls = applicationContext.getBean("cls", Cls.class);
logger.info("List集合类型属性赋值:{}", cls);
}
public class Family {
private String familyName;
private Map<String, Mem> memMap;
// 无参构造函数
// 全参构造函数
// getter setter toString
}
public class Mem {
private String memName;
private Integer memAge;
// 无参构造函数
// 全参构造函数
// getter setter toString
}
<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="mem1" class="com.giser.spring6.iocmap.Mem">
<property name="memAge" value="11" />
<property name="memName" value="小李" />
bean>
<bean id="mem2" class="com.giser.spring6.iocmap.Mem">
<property name="memAge" value="22" />
<property name="memName" value="小张"/>
bean>
<bean id="family" class="com.giser.spring6.iocmap.Family">
<property name="familyName" value="梦想家" />
<property name="memMap">
<map>
<entry>
<key>
<value>1001value>
key>
<ref bean="mem1"/>
entry>
<entry>
<key>
<value>1002value>
key>
<ref bean="mem2"/>
entry>
map>
property>
bean>
<bean id="family2" class="com.giser.spring6.iocmap.Family">
<property name="familyName" value="梦想家" />
<property name="memMap">
<map>
<entry value-ref="mem1">
<key>
<value>1001value>
key>
entry>
<entry value-ref="mem2">
<key>
<value>1002value>
key>
entry>
map>
property>
bean>
beans>
public class SpringMapDITest {
private Logger logger = LoggerFactory.getLogger(SpringMapDITest.class);
@Test
public void testSpecialVal(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-map-di.xml");
Family family = applicationContext.getBean("family", Family.class);
logger.info("对象类型属性赋值:{}", family);
Family family2 = applicationContext.getBean("family2", Family.class);
logger.info("对象类型属性赋值:{}", family2);
}
}
public class Family {
private String familyName;
private Map<String, Mem> memMap;
private List<Mem> memList;
// 无参构造函数
// 全参构造函数
// getter setter toString
public class Mem {
private String memName;
private Integer memAge;
// 无参构造函数
// 全参构造函数
// getter setter toString
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="family" class="com.giser.spring6.iocref.Family">
<property name="familyName" value="一家人" />
<property name="memMap" ref="memMap" />
<property name="memList" ref="memList" />
bean>
<util:list id="memList">
<ref bean="mem1" />
<ref bean="mem2" />
<ref bean="mem3" />
util:list>
<util:map id="memMap">
<entry>
<key>
<value>1001value>
key>
<ref bean="mem1"/>
entry>
<entry>
<key>
<value>1002value>
key>
<ref bean="mem2"/>
entry>
util:map>
<bean id="mem1" class="com.giser.spring6.iocref.Mem">
<property name="memAge" value="11" />
<property name="memName" value="小李" />
bean>
<bean id="mem2" class="com.giser.spring6.iocref.Mem">
<property name="memAge" value="22" />
<property name="memName" value="小张"/>
bean>
<bean id="mem3" class="com.giser.spring6.iocref.Mem">
<property name="memAge" value="33" />
<property name="memName" value="小王"/>
bean>
beans>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="family" class="com.giser.spring6.iocref.Family"
p:familyName="一家人"
p:memMap-ref="memMap"
p:memList-ref="memList"
>
bean>
<util:list id="memList">
<ref bean="mem1" />
<ref bean="mem2" />
<ref bean="mem3" />
util:list>
<util:map id="memMap">
<entry>
<key>
<value>1001value>
key>
<ref bean="mem1"/>
entry>
<entry>
<key>
<value>1002value>
key>
<ref bean="mem2"/>
entry>
util:map>
<bean id="mem1" class="com.giser.spring6.iocref.Mem">
<property name="memAge" value="11" />
<property name="memName" value="小李" />
bean>
<bean id="mem2" class="com.giser.spring6.iocref.Mem">
<property name="memAge" value="22" />
<property name="memName" value="小张"/>
bean>
<bean id="mem3" class="com.giser.spring6.iocref.Mem">
<property name="memAge" value="33" />
<property name="memName" value="小王"/>
bean>
beans>
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-p-di.xml");
Family family = applicationContext.getBean("family", Family.class);
logger.info("p标签属性赋值:{}", family);
jdbc.properties
jdbc.user=root
jdbc.password=root
jdbc.url=jdbc:mysql://localhost:3306/db_mybatis?serverTimezone=UTC
jdbc.driver=com.mysql.cj.jdbc.Driver
beans-jdbc.xml
<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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<context:property-placeholder location="classpath:jdbc.properties" />
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="password" value="${jdbc.password}" />
<property name="username" value="${jdbc.user}" />
<property name="driverClassName" value="${jdbc.driver}" />
bean>
beans>
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-ds.xml");
DruidDataSource druidDataSource = applicationContext.getBean(DruidDataSource.class);
logger.info("数据库对象:{}", druidDataSource);
<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="apple" class="com.giser.spring6.scope.Apple" scope="prototype" />
beans>
public class SpringScopeTest {
private final Logger logger = LoggerFactory.getLogger(SpringScopeTest.class);
/**
* scope=singleton时:
* [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'apple'
* [main] INFO spring6.SpringScopeTest - 单例对象:com.giser.spring6.scope.Apple@436390f4
* [main] INFO spring6.SpringScopeTest - 单例对象:com.giser.spring6.scope.Apple@436390f4
*
* scope="prototype"时:
* [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 1 bean definitions from class path resource [beans-scope.xml]
* [main] INFO spring6.SpringScopeTest - 单例对象:com.giser.spring6.scope.Apple@733037
* [main] INFO spring6.SpringScopeTest - 单例对象:com.giser.spring6.scope.Apple@7728643a
*
* 如果是在WebApplicationContext环境下还会有另外几个作用域(但不常用)
* request:在一个请求域内有效
* session:在一个会话范围内有效
*/
@Test
public void testScope(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-scope.xml");
Apple apple = applicationContext.getBean(Apple.class);
logger.info("单例对象:{}", apple);
Apple apple2 = applicationContext.getBean(Apple.class);
logger.info("单例对象:{}", apple2);
}
}
package com.giser.spring6.lifecycle;
/**
* @author giserDev
* @description
* @date 2023-12-31 21:22:01
*/
public class Phone {
private String phoneName;
public Phone() {
System.out.println("Bean生命周期:[1 bean对象创建(调用无参构造方法)]");
}
public void initMethod(){
System.out.println("Bean生命周期:[4 bean对象初始化(调用bean配置时init-method属性指定的初始化方法)] ");
}
public void destroyMethod(){
System.out.println("Bean生命周期:[7 bean对象销毁(调用bean配置时destroy-method属性指定的销毁方法)] ");
}
public String getPhoneName() {
return phoneName;
}
public void setPhoneName(String phoneName) {
System.out.println("Bean生命周期:[2 为对象属性赋值(调用属性set方法)] ");
this.phoneName = phoneName;
}
}
package com.giser.spring6.lifecycle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* @author giserDev
* @description
* @date 2023-12-31 21:26:40
*/
public class MyBeanProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean生命周期:[3 bean后置处理器(在bean初始化之前执行)] ");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean生命周期:[5 bean后置处理器(在bean初始化之后执行)] ");
return bean;
}
}
<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="phone" class="com.giser.spring6.lifecycle.Phone"
init-method="initMethod"
destroy-method="destroyMethod"
scope="singleton" >
<property name="phoneName" value="小米手机" />
bean>
<bean id="myBeanProcessor" class="com.giser.spring6.lifecycle.MyBeanProcessor" />
beans>
import com.giser.spring6.lifecycle.Phone;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author giserDev
* @description
* @date 2023-12-31 21:30:42
*/
public class SpringBeanLifeCycleTest {
private Logger logger = LoggerFactory.getLogger(SpringBeanLifeCycleTest.class);
/**
* 在scope="singleton"情况下:
* 2023-12-31 22:09:45 404 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@422c3c7a
* 2023-12-31 22:09:45 631 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 2 bean definitions from class path resource [beans-lifecycle.xml]
* 2023-12-31 22:09:45 679 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myBeanProcessor'
* 2023-12-31 22:09:45 713 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'phone'
* Bean生命周期:[1 bean对象创建(调用无参构造方法)]
* Bean生命周期:[2 为对象属性赋值(调用属性set方法)]
* Bean生命周期:[3 bean后置处理器(在bean初始化之前执行)]
* Bean生命周期:[4 bean对象初始化(调用bean配置时init-method属性指定的初始化方法)]
* Bean生命周期:[5 bean后置处理器(在bean初始化之后执行)]
* 2023-12-31 22:09:45 787 [main] INFO spring6.SpringBeanLifeCycleTest - Bean生命周期:[6 bean对象准备就绪,可以使用了]
* 2023-12-31 22:09:45 789 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Closing org.springframework.context.support.ClassPathXmlApplicationContext@422c3c7a, started on Sun Dec 31 22:09:45 CST 2023
* Bean生命周期:[7 bean对象销毁(调用bean配置时destroy-method属性指定的销毁方法)]
* 2023-12-31 22:09:45 793 [main] DEBUG org.springframework.beans.factory.support.DisposableBeanAdapter - Custom destroy method 'destroyMethod' on bean with name 'phone' completed
*/
@Test
public void test01(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-lifecycle.xml");
Phone phone = applicationContext.getBean(Phone.class);
logger.info("Bean生命周期:[6 bean对象准备就绪,可以使用了]");
applicationContext.close();
}
}
public class UserInfo {
}
public class UserFactoryBean implements FactoryBean<UserInfo> {
@Override
public UserInfo getObject() throws Exception {
return new UserInfo();
}
@Override
public Class<?> getObjectType() {
return UserInfo.class;
}
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
<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="userInfo" class="com.giser.spring6.factorybean.UserFactoryBean" />
beans>
public class SpringFactoryBeanTest {
private Logger logger = LoggerFactory.getLogger(SpringFactoryBeanTest.class);
/**
* FactoryBean是Spring提供的一种整合第三方框架的常用机制。
* 和普通的bean不同,配置一个FactoryBean类型的bean,
* 在获取bean的时候得到的并不是class属性中配置的这个类的对象,
* 而是getObject()方法的返回值。
* 在整合Mybatis时,Spring就是通过FactoryBean机制来帮我们创建SqlSessionFactory对象的。
*
* [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@14b030a0
* [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 1 bean definitions from class path resource [beans-factorybean.xml]
* [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'userInfo'
* [main] INFO spring6.SpringFactoryBeanTest - 通过FactoryBean获取的对象为com.giser.spring6.factorybean.UserInfo@255990cc
*/
@Test
public void testFactoryBean(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-factorybean.xml");
UserInfo userInfo = applicationContext.getBean(UserInfo.class);
logger.info("通过FactoryBean获取的对象为{}", userInfo);
}
}
UserDao
public interface UserDao {
void sayHello();
}
public class UserDaoImpl implements UserDao {
@Override
public void sayHello() {
System.out.println("userDao sayHello");
}
}
UserService
public interface UserService {
void sayHello();
}
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void sayHello() {
userDao.sayHello();
}
}
UserController
public class UserController {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public void sayHello(){
userService.sayHello();
}
}
自动装配
<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="userController" class="com.giser.spring6.autowire.controller.UserController" autowire="byName" />
<bean id="userService" class="com.giser.spring6.autowire.service.impl.UserServiceImpl" autowire="byName" />
<bean id="userDao" class="com.giser.spring6.autowire.dao.impl.UserDaoImpl" autowire="byName" />
beans>
测试
import com.giser.spring6.autowire.controller.UserController;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author giserDev
* @description
* @date 2023-12-31 22:51:15
*/
public class SpringAutowiredTest {
@Test
public void testAutowired(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-autowire.xml");
UserController userController = applicationContext.getBean(UserController.class);
userController.sayHello();
}
}
从 Java 5 开始,Java 增加了对注解(Annotation)的支持,它是代码中的一种特殊标记,可以在编译、类加载和运行时被读取,执行相应的处理。Spring 从 2.5 版本开始提供了对注解技术的全面支持,我们可以使用注解来实现自动装配,简化 Spring 的 XML 配置。
Spring 通过注解实现自动装配的步骤如下:
创建子模块giser-java-spring6-ioc-annotation,并引入配置文件beans.xml、log4j2.xml,添加如下依赖:
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
dependency>
<dependency>
<groupId>org.junit.jupitergroupId>
<artifactId>junit-jupiter-apiartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-coreartifactId>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-slf4j2-implartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
dependency>
<dependency>
<groupId>jakarta.annotationgroupId>
<artifactId>jakarta.annotation-apiartifactId>
<version>2.1.1version>
dependency>
dependencies>
Spring 默认不使用注解装配 Bean,因此我们需要在 Spring 的 XML 配置中,通过 context:component-scan 元素开启 Spring Beans的自动扫描功能。开启此功能后,Spring 会自动从扫描指定的包(base-package 属性设置)及其子包下的所有类,如果类上使用了 @Component 注解,就将该类装配到容器中。示例如下:
<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">
<context:component-scan base-package="com.giser.spring6.anno" />
beans>
注意: 在使用 context:component-scan 元素开启自动扫描功能前,首先需要在 XML 配置的一级标签 中添加 context 相关的约束。
有三种情况:
<context:component-scan base-package="com.giser.spring6.anno" />
<context:component-scan base-package="com.giser.spring6.anno" >
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
context:component-scan>
<context:component-scan base-package="com.giser.spring6.anno" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
context:component-scan>
此注解可以用在构造方法上、方法上、形参上、属性上、注解上。
@Autowired
private UserService userService;
private UserService userService;
/**
* 通过set方法注入
* @param userService
*/
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
private UserService userService;
/**
* 根据构造方法注入
* Autowiring by type from bean name 'userController' via constructor to bean named 'userServiceImpl'
* @param userService
*/
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
private UserService userService;
/**
* 形参上注入
* Autowiring by type from bean name 'userController' via constructor to bean named 'userServiceImpl'
* @param userService
*/
public UserController(@Autowired UserService userService) {
this.userService = userService;
}
private UserService userService;
/**
* 只有一个构造函数时,无需注解也可以注入
* Autowiring by type from bean name 'userController' via constructor to bean named 'userServiceImpl'
* @param userService
*/
public UserController(UserService userService) {
this.userService = userService;
}
/**
* @Autowired默认是根据类型注入的,如果需要根据名称注入,需添加@Qualifier注解
*
*/
@Autowired
@Qualifier("userDaoImpl")
private UserDao userDao;
使用@Resource注解需要引入以下坐标:
<dependency>
<groupId>jakarta.annotationgroupId>
<artifactId>jakarta.annotation-apiartifactId>
dependency>
/**
* 根据名称注入
* 默认byName注入,没有指定name时把属性名当做name,根据name找不到时,才会byType注入。
* byType注入时,某种类型的Bean只能有一个.
* 当@Resource注解使用时没有指定name的时候,还是根据name进行查找,这个name是属性名
*/
@Resource(name = "myUserService")
private UserService userService;
创建配置类
@Configuration
@ComponentScan(basePackages = "com.giser.spring6.anno")
public class SpringConfig {
}
@Test
public void testFullAnno(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
MyUserController myUserController = applicationContext.getBean("myUserController", MyUserController.class);
myUserController.exec();
}