Bean
配置
在 Spring 中,配置 bean 实例一般使用 xml 配置方式或注解(Annontation)配置方式。
xml 配置
在 xml 配置中分为三种方式,分别为反射模式、工厂方法模式和 Factory Bean 模式。
反射模式:指通过指定 bean 的 class 属性值来创建对象(最为常用,前面的文章一直使用该模式)
工厂方法模式:指通过反射机制获取 Factory 类,再利用 Factory 类来创建对象
Factory Bean 模式:指通过实现 FactoryBean 接口中的 getObject() 方法来返回 bean 对象实例。通常 Factory Bean 模式用来配置第三方框架中的 bean 对象
反射模式
反射模式在 bean 配置中需要配置 bean 对象的全类名。
<bean id="beanObject" class="cn.edu.springdemo.beanDemo.beanObject" p:instance="beanObject" />
工厂方法模式
工厂方法分为静态工厂方法和实例工厂方法。工厂方法模式简单了解即可。
静态工厂方法指 Factory 类本身不需要实例化,但其提供了一个静态方法来创建对象。
简单示例:
创建一个学科类:
package cn.edu.springdemo.beanDemo;
//学科类
public class Discipline {
private int id;
private String discipline;
public Discipline() {
super();
}
public Discipline(int id, String discipline) {
this.id = id;
this.discipline = discipline;
}
public int getId() {
return id;
}
public String getDiscipline() {
return discipline;
}
public void setId(int id) {
this.id = id;
}
public void setDiscipline(String discipline) {
this.discipline = discipline;
}
@Override
public String toString() {
return "Discipline{" +
"id=" + id +
", discipline='" + discipline + '\'' +
'}';
}
}
创建一个对应学科类的静态工厂类:
package cn.edu.springdemo.beanDemo;
import java.util.HashMap;
import java.util.Map;
public class DisciplineStaticFactory {
private static Map<Integer,Discipline> map = new HashMap<Integer, Discipline>();
//静态 bean 容器,存储学科类对象的集合
static {
map.put(1,new Discipline(20230502,"计算机"));
map.put(2,new Discipline(20230504,"数学"));
map.put(3,new Discipline(20230506,"英语"));
}
//提供一个静态方法,根据其 id 获取对应的对象
public static Discipline getDiscipline(int id) {
return map.get(id);
}
}
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">
<!-- id为学科类的一个实例;但 class 属性指向的是静态工厂类;factory-method 属性指向的是静态工厂类的静态方法 -->
<bean id="math" class="cn.edu.springdemo.beanDemo.DisciplineStaticFactory"
factory-method="getDiscipline">
<!-- 给静态工厂类的静态方法传递参数 -->
<constructor-arg value="2"></constructor-arg>
</bean>
</beans>
测试结果:
package cn.edu.springdemo.test;
import cn.edu.springdemo.beanDemo.Discipline;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AdminTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beanConfiguration.xml");
Discipline discipline = (Discipline) applicationContext.getBean("math");
System.out.println(discipline);
}
}
结果如图:
实例工厂方法指通过实例工厂对象来调用 getBean 方法获取 bean 对象。
简单示例:
与学科类一样,再创建一个对应学科类的实例工厂类:
package cn.edu.springdemo.beanDemo;
import java.util.HashMap;
import java.util.Map;
public class DisciplineInstanceFactory {
private Map<Integer,Discipline> map = new HashMap<>();
public void setMap(Map<Integer, Discipline> map) {
this.map = map;
}
//根据其 key 获取对应的对象
public Discipline getDiscipline(int key){
return map.get(key);
}
}
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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置工厂实例 -->
<bean id="disciplineInstanceFactory" class="cn.edu.springdemo.beanDemo.DisciplineInstanceFactory">
<property name="map">
<map>
<entry key="1">
<bean class="cn.edu.springdemo.beanDemo.Discipline" p:id="20230502" p:discipline="计算机" />
</entry>
<entry key="2">
<bean class="cn.edu.springdemo.beanDemo.Discipline" p:id="20230504" p:discipline="数学" />
</entry>
<entry key="3">
<bean class="cn.edu.springdemo.beanDemo.Discipline" p:id="20230506" p:discipline="英语" />
</entry>
</map>
</property>
</bean>
<!-- 配置获取相应的实例 -->
<bean id="math" factory-bean="disciplineInstanceFactory" factory-method="getDiscipline">
<constructor-arg value="2"></constructor-arg>
</bean>
</beans>
结果如图:
Factory Bean 模式
Factory Bean 模式中需要实现 Factory Bean 接口,其中包括三个方法:getObject() 、getObjectType() 、isSingleton() 。
简单示例:
与学科类一样,再创建一个 Factory Bean 接口实现类:
package cn.edu.springdemo.beanDemo;
import org.springframework.beans.factory.FactoryBean;
public class DisciplineFactoryBean implements FactoryBean<Discipline> {
private int id;
private String discipline;
//set 方法
public void setId(int id) {
this.id = id;
}
public void setDiscipline(String discipline) {
this.discipline = discipline;
}
//返回配置的 bean 对象实例
@Override
public Discipline getObject() throws Exception {
return new Discipline(id,discipline);
}
//返回配置的 bean 对象的类型
@Override
public Class<?> getObjectType() {
return Discipline.class;
}
//是否为单例
@Override
public boolean isSingleton() {
return true;
}
}
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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 通过 FactoryBean 配置 bean 实例,getObject() 方法返回 -->
<bean id="math" class="cn.edu.springdemo.beanDemo.DisciplineFactoryBean" p:id="20230514" p:discipline="math" />
</beans>
结果如图:
另外,使用 Factory Bean 模式将 Quartz框架(第三方框架)整合到 Spring 中。Quartz 是一个完全由 Java 编写的开源作业调度框架,可以用来创建简单或运行十个、百个,甚至是好几万个 Jobs 这样复杂的程序。
简单示例:
先在 pom.xml 中添加以下依赖:
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.3.25</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.25</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-nop -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>2.0.6</version>
<type>jar</type>
</dependency>
<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
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">
<!-- 定义工作任务Job -->
<bean name="quartzJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<!-- 指定 Job 名称 -->
<property name="name" value="QuartzJob" />
<!-- 指定 Job 分组 -->
<property name="group" value="QuartzJobGroup" />
<!-- 指定 Job 接口实现类 -->
<property name="jobClass" value="cn.edu.springdemo.beanDemo.QuartzJob" />
<!-- 指定 value 值必须为 true ,否则 Job 执行完成后不会再继续 -->
<property name="durability" value="true" />
<!-- 指定 spring 容器的 Key -->
<property name="applicationContextJobDataKey" value="QuartzJob" />
</bean>
<!-- 定义与工作任务绑定的触发器Trigger -->
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<!-- 指定 Trigger 名称 -->
<property name="name" value="CronTrigger" />
<!-- 指定 Trigger 分组 -->
<property name="group" value="CronTriggerGroup" />
<!-- 指定 Trigger 绑定的工作任务 -->
<!-- 多个工作任务用 jobDataMap -->
<property name="jobDetail" ref="quartzJob" />
<!-- 指定 CronExpression 表达式,每隔多长时间执行一次 -->
<!--
写法:秒 分 时 日 月 周 年
通配符:*表示所有值;
?表示不定值;
-表示区间;
,表示指定多个值;
/表示从某个时间开始,每隔一段时间触发一次
-->
<!-- 从十秒开始,每隔8秒触发一次 -->
<property name="cronExpression" value="10/8 * * * * ?" />
</bean>
<!-- 定义调度器,将 Trigger 注册到 Scheduler -->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTrigger" />
</list>
</property>
</bean>
</beans>
再创建一个 Job 接口的实现类:
package cn.edu.springdemo.beanDemo;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class QuartzJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("定时执行的工作任务");
}
}
测试结果:
package cn.edu.springdemo.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
public class QuartzJobTest {
public static void main(String[] args) {
ApplicationContext QuartzJob = new ClassPathXmlApplicationContext("QuartzJob.xml");
SchedulerFactoryBean scheduler = QuartzJob.getBean(SchedulerFactoryBean.class);
scheduler.start();
}
}
结果如图: