Spring入门&IOC&DI

本文详细介绍Spring框架的基础知识,包括Spring的结构、IOC与DI概念、工厂类使用、配置管理、Bean生命周期与作用范围,以及Spring中Bean的实例化与属性注入方式。同时,深入探讨Spring的注解开发,对比XML与注解开发,最后讲解Spring的模块化开发与项目优化策略。

目录

一.了解Spring

二.Spring入门

2.1 Spring开发包

2.2 创建项目引入jar包

三.IOC&DI

3.1 IOC

3.1.1 IOC的主题引入

3.1.2 IOC解决上述问题

3.2 DI

四.Spring工厂类

4.1 工厂类结构图

4.2 BeanFactory (老版本的工厂类)

4.3 ApplicationContext (新版本的工厂类)

五.Spring的配置

5.1 Schema本地的配置

5.2 Bean的相关配置

5.2.1  标签的id和name的配置

5.2.2 Bean的生命周期的配置

5.2.3 Bean的作用范围的配置(重点)

六.SpringIOC中bean的管理(XML)

6.1 Spring中Bean的实例化方式

6.1.1 无参构造方法的方式(默认)

6.1.2 静态工厂实例化的方式

6.1.3 实例工厂实例化的方式

6.2 Spring的属性注入

6.2.1 构造方法的方式的属性注入

6.2.2 set方法的方式的属性注入

6.2.3 set方法设置对象类型的属性

6.2.4 P名称空间的属性注入(Spring2.5以后)

6.2.5 SpEL的属性注入(Spring3.0以后)

6.2.6 集合类型属性注入

七.SpringIOC的注解开发

7.1 注解开发入门 

7.2 Spring注解详解

7.2.1 Component 组件

7.2.2 属性注入的注解

7.2.3 其它注解

7.3 IOC的XML和注解开发比较

7.4 XML和注解的整合开发

八.Spring分模块开发与项目优化

8.1 引入配置文件

8.2 Spring项目优化

8.2.1 问题:

8.2.2 解决方案:


一.了解Spring

  • Spring:SE/EE开发的一站式框架(有EE开发的每一层解决方案)
    • WEB层            :SpringMVC
    • Service层        :Spring的Bean管理,Spring声明式事务
    • DAO层             :Spring的Jdbc模板,Spring的ORM模块

功能: 

二.Spring入门

2.1 Spring开发包

  • docs          :Spring的开发规范和API
  • libs             :Spring的开发的jar和源码
  • schema     :Spring的配置文件的约束

2.2 创建项目引入jar包

在 Sping开发包中找到以下jar包并引入项目

三.IOC&DI

3.1 IOC

IOC: Inversion of Control(控制反转)。

控制反转:将对象的创建权反转给(交给)Spring。

3.1.1 IOC的主题引入

以往我们在项目中处理dao层通常用下面这种方式

/**
 * 用户管理DAO层接口
 *
 */
public interface UserDAO {
	public void save();
}
/**
 * 用户管理DAO层实现类
 *
 */
public class UserDAOImpl implements UserDAO {

	@Override
	public void save() {
		System.out.println("UserDAOImpl执行了...");
	}

}
	/**
	 * 传统方式的调用
	 */
	public void demo1(){
		UserDAOImpl userDAO = new UserDAOImpl();
		userDAO.save();
	}

问题:

如果底层的实现切换了,需要修改源代码,比如说原本对数据库的操作用的是JDBC,现在要切换成Hibernate,是否可以不修改程序源代码对程序进行扩展?

3.1.2 IOC解决上述问题

① 配置XML文件,将实现类交给Spring管理

在项目的src目录下增加配置文件名为 applicationContext.xml

在spring的解压路径下spring-framework-4.2.4.RELEASE\docs\spring-framework-reference\html\xsd-configuration.html 中最下方复制约束放入该配置文件,并在该文件中配置实现类。

<?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">
	<!-- Spring的入门的配置==================== -->
 	<bean id="userDAO" class="com.spring.demo1.UserDAOImpl" >
 	</bean>
</beans>

② 编写测试方法

@Test
public void test02(){
	// 创建Spring的工厂
	ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
	UserDao userDao = (UserDao) applicationContext.getBean("userDao");
	userDao.save();
}

3.2 DI

依赖注入,前提必须有IOC的环境,Spring管理这个类的时候将类的依赖的属性注入(设置)进来,即在Spring实例化该类时,其中的属性也自动赋值,修改上述 UserDaoImpl实现类增加 name 属性,并设置 set 方法。

/**
 * 用户管理DAO层实现类
 *
 */
public class UserDAOImpl implements UserDAO {
	private String name;

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public void save() {
		System.out.println("UserDAOImpl执行了..."+name);
	}

}

修改配置文件加入属性

<bean id="userDAO" class="com.itheima.spring.demo1.UserDAOImpl" >
    <property name="name" value="李东"/>
</bean>

重新运行上述测试类,运行结果为:

四.Spring工厂类

4.1 工厂类结构图

4.2 BeanFactory (老版本的工厂类)

特征:调用getBean的时候,才会生成类的实例

4.3 ApplicationContext (新版本的工厂类)

特征:加载配置文件的时候,就会将Spring管理的类都实例化。

ApplicationContext 有两个实现类

ClassPathXmlApplicationContext:加载类路径下的配置文件

FileSystemXmlApplicationContext:加载文件系统下的配置文件

/**
 * 加载磁盘上的配置文件
 */
public void demo3(){
	ApplicationContext applicationContext = new FileSystemXmlApplicationContext("C:\\applicationContext.xml");
	UserDAO userDAO = (UserDAO) applicationContext.getBean("userDAO");
	userDAO.save();
}

五.Spring的配置

5.1 Schema本地的配置

① 设置 Key 将下面这句话填入key中

② 设置 Location解压:spring-framework-4.2.4.RELEASE-schema.zip 在beans 目录下 选择 spring-beans-4.2.xsd

③ 设置 KeyType

5.2 Bean的相关配置

5.2.1  <bean>标签的id和name的配置

  • id           :使用了约束中的唯一约束。里面不能出现特殊字符的。
  • name     :没有使用约束中的唯一约束(理论上可以出现重复的,但是实际开发不能出现的),里面可以出现特殊字符,其余                     功能与id相同。应用在Spring和Struts1框架整合的时候 <bean name=”/user” class=””/>

5.2.2 Bean的生命周期的配置

  • init-method              :Bean被初始化的时候执行的方法
  • destroy-method       :Bean被销毁的时候执行的方法(Bean是单例创建,工厂关闭)

案例:

① 新建接口 CustomerDao 和 CustomerDaoImpl

public interface CustomerDao {
	public void save();
}
public class CustomerDaoImpl implements CustomerDao {
	
	public void setup(){
		System.out.println("CustomerDAOImpl被初始化了...");
	}

	@Override
	public void save() {
		System.out.println("CustomerDAOImpl的save方法执行了...");
	}
	
	public void destroy(){
		System.out.println("CustomerDAOImpl被销毁了...");
	}

}

② 在applicationContext.xml中增加如下配置

 		<!-- Spring的sBean的生命周期的配置=========== -->
<bean id="customerDao" class="dao.impl.CustomerDaoImpl" init-method="setup" destroy-method="destroy"/>

③ 编写测试方法

/**
 * 生命周期的配置
 */
public void test03(){
	ClassPathXmlApplicationContext applicationContext= new ClassPathXmlApplicationContext("applicationContext.xml");
	CustomerDao customerDAO = (CustomerDao) applicationContext.getBean("customerDao");
	customerDAO.save();
	applicationContext.close();
}

运行结果:

5.2.3 Bean的作用范围的配置(重点)

  • scope                          :Bean的作用范围
    • singleton                  :默认的,Spring会采用单例模式创建这个对象。
    • prototype       :多例模式。(Struts2和Spring整合一定会用到)
    • request             :应用在web项目中,Spring创建这个类以后,将这个类存入到request范围中。
    • session             :应用在web项目中,Spring创建这个类以后,将这个类存入到session范围中。
    • globalsession  :应用在web项目中,必须在porlet环境下使用。但是如果没有这种环境,相对于session。

XML配置案例:

 		<!-- Spring的sBean的生命周期的配置=========== -->
<bean id="customerDao" class="dao.impl.CustomerDaoImpl" init-method="setup" destroy-method="destroy" scope="prototype" />

六.SpringIOC中bean的管理(XML)

6.1 Spring中Bean的实例化方式

Bean已经都交给Spring管理,Spring创建这些类的时候,有几种方式:

6.1.1 无参构造方法的方式(默认)

/**
 * 无参数构造方法方式
 *
 */
public class Bean1 {

	public Bean1() {
		super();
		System.out.println("Bean1的无参数的构造方法执行了...");
	}

}
	<!-- 无参数构造方法 -->
<bean id="bean1" class="test.Bean1"></bean>
public void test05(){
	ClassPathXmlApplicationContext applicationContext= new ClassPathXmlApplicationContext("applicationContext.xml");
	Bean1 b1 = (Bean1) applicationContext.getBean("bean1");
}

运行结果:

6.1.2 静态工厂实例化的方式

① 编写Bean2的静态工厂

/**
 * Bean2的静态工厂
 *
 */
public class Bean2Factory {

	public static Bean2 createBean2(){
		System.out.println("Bean2Factory中方法执行了...");
		return new Bean2();
	}
}

② 配置xml文件

	<!-- 静态工厂实例化 -->
<bean id="bean2" class="test.Bean2Factory" factory-method="createBean2"/>

③编写测试方法

/**
 * 静态工厂实例化
 */
public void demo2(){
	ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
	Bean2 bean2 = (Bean2) applicationContext.getBean("bean2");
	System.out.println(bean2);
}

6.1.3 实例工厂实例化的方式

① 编写Bean3的实例工厂

/**
 * Bean3的实例工厂
 *
 */
public class Bean3Factory {

	public Bean3 createBean3(){
		System.out.println("Bean3的实例工厂执行了...");
		return new Bean3();
	}
}

② 配置xml文件

	<!-- 实例工厂实例化 -->
<bean id="bean3Factory" class="test.Bean3Factory"></bean> 
<bean id="bean3" factory-bean="bean3Factory" factory-method="createBean3"></bean> 

③编写测试方法

/**
 * 实例工厂实例化
 */
public void demo3(){
	ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
	Bean3 bean3 = (Bean3) applicationContext.getBean("bean3");
	System.out.println(bean3);
}

6.2 Spring的属性注入

6.2.1 构造方法的方式的属性注入

①编写汽车类

public class Car {
	private String name;
	private Double price;
	
	public Car(String name, Double price) {
		super();
		this.name = name;
		this.price = price;
	}

	@Override
	public String toString() {
		return "Car [name=" + name + ", price=" + price + "]";
	}
	
}

②配置xml文件 

	<!-- 构造方法的方式 -->
	<bean id="car" class="demo4.Car">
		<constructor-arg name="name" value="宝马"/>
		<constructor-arg name="price" value="800000"/>
	</bean>

③测试方法

@Test
/**
 * 构造方法方式的属性注入
 */
public void demo1(){
	ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
	Car car = (Car) applicationContext.getBean("car");
	System.out.println(car);
}

6.2.2 set方法的方式的属性注入

①实体类

/**
 * set方法的属性注入
 *
 */
public class Car2 {
	private String name;
	private Double price;
	public void setName(String name) {
		this.name = name;
	}
	public void setPrice(Double price) {
		this.price = price;
	}
	@Override
	public String toString() {
		return "Car2 [name=" + name + ", price=" + price + "]";
	}
	
}

②配置xml文件

	<!-- set方法的方式 -->
  	<bean id="car2" class="demo4.Car2">
		<property name="name" value="奔驰"/>
		<property name="price" value="1000000"/>
	</bean> 

③测试方法

/**
 * set方法方式的属性注入
 */
public void demo2(){
	ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
	Car2 car2 = (Car2) applicationContext.getBean("car2");
	System.out.println(car2);
}

6.2.3 set方法设置对象类型的属性

①实体类

public class Employee {
	private String name;
	private Car2 car2;
	public void setName(String name) {
		this.name = name;
	}
	public void setCar2(Car2 car2) {
		this.car2 = car2;
	}
	@Override
	public String toString() {
		return "Employee [name=" + name + ", car2=" + car2 + "]";
	}
}

②配置xml文件

		<!-- set方法注入对象类型的属性 -->
	<bean id="employee" class="demo4.Employee">
		<!-- value:设置普通类型的值,ref:设置其他的类的id或name -->
		<property name="name" value="涛哥"/>
		<property name="car2" ref="car2"/>
	</bean> 
	<bean id="car2" class="demo4.Car2">
		<property name="name" value="奔驰"/>
		<property name="price" value="1000000"/>
	</bean>	

③测试方法

@Test
/**
 * set方法注入对象类型
 */
public void demo3(){
	ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
	Employee employee = (Employee) applicationContext.getBean("employee");
	System.out.println(employee);
}

6.2.4 P名称空间的属性注入(Spring2.5以后)

在约束中加入下面这句

配置类

		<!-- 改为p名称空间的方式 -->
	<bean id="car2" class="demo4.Car2" p:name="奇瑞QQ" p:price="30000"></bean>
	
	<bean id="employee" class="demo4.Employee" p:name="王东" p:car2-ref="car2"></bean>

6.2.5 SpEL的属性注入(Spring3.0以后)

SpEL:Spring Expression Language,Spring的表达式语言。

语法:#{SpEL}

编写实体类 CarInfo

public class CarInfo {
	private String name;
	
	public String getName() {
		return "摩托车";
	}
	
	public Double calculatorPrice(){
		return Math.random() * 3000;
	}
}

修改xml文件

		<!-- SpEL的属性注入 -->
	<bean id="carInfo" class="demo4.CarInfo">
	</bean>
	
	<bean id="car2" class="demo4.Car2">
		<property name="name" value="#{carInfo.name}"></property>
		<property name="price" value="#{carInfo.calculatorPrice()}"></property>
	</bean>
	
	<bean id="employee" class="demo4.Employee">
		<property name="name" value="#{'赵洪'}"></property>
		<property name="car2" value="#{car2}"></property>
	</bean>

6.2.6 集合类型属性注入

①实体类

/**
 * 集合属性的注入:
 *
 */
public class CollectionBean {
	private String[] arrs;
	private List<String> list;
	private Set<String> set;
	private Map<String,String> map;

	public void setArrs(String[] arrs) {
		this.arrs = arrs;
	}

	public void setList(List<String> list) {
		this.list = list;
	}

	public void setSet(Set<String> set) {
		this.set = set;
	}

	public void setMap(Map<String, String> map) {
		this.map = map;
	}

	@Override
	public String toString() {
		return "CollectionBean [arrs=" + Arrays.toString(arrs) + ", list=" + list + ", set=" + set + ", map=" + map
				+ "]";
	}

	
}

②配置xml文件

	<!-- Spring的集合属性的注入============================ -->
	<!-- 注入数组类型 -->
	<bean id="collectionBean" class="demo4.CollectionBean">
		<!-- 数组类型 -->
		<property name="arrs">
			<list>
				<value>王东</value>
				<value>赵洪</value>
				<value>李冠希</value>
			</list>
		</property>
		
		<!-- 注入list集合 -->
		<property name="list">
			<list>
				<value>李兵</value>
				<value>赵如何</value>
				<value>邓凤</value>
			</list>
		</property>
		
		<!-- 注入set集合 -->
		<property name="set">
			<set>
				<value>aaa</value>
				<value>bbb</value>
				<value>ccc</value>
			</set>
		</property>
		
		<!-- 注入Map集合 -->
		<property name="map">
			<map>
				<entry key="aaa" value="111"/>
				<entry key="bbb" value="222"/>
				<entry key="ccc" value="333"/>
			</map>
		</property>
	</bean>

③测试类

@Test
public void demo1() {
	ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
	
	CollectionBean collectionBean = (CollectionBean) applicationContext.getBean("collectionBean");
	System.out.println(collectionBean);
}

七.SpringIOC的注解开发

7.1 注解开发入门 

① 创建web项目,引入jar包

在Spring4中除了引入基本的开发包,还要引入aop包(Spring3中不需要)

 

②  引入配置文件

在src目录下新建 applicationContext.xml,进行注解开发则需要在其中引入context约束(之前引入的是beans约束)

该约束路径:spring-framework-4.2.4.RELEASE-dist\spring-framework-4.2.4.RELEASE\docs\spring-framework-reference\html\xsd-configuration.html

<?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">

</beans>

③ 创建接口和实现类

public interface UserDao {
	public void save();
}
public class UserDaoImpl implements UserDao {

	@Override
	public void save() {
		System.out.println("dao中保存用户的方法执行了。。。");
	}

}

④ 开启注解扫描并添加注解

	<!-- 指定扫描dao包下的所有类中的注解.注意:扫描包时.会扫描指定包下的所有子孙包 -->
	<context:component-scan base-package="dao"></context:component-scan>
@Component("userDao") //相当于 xml管理方式的 <bean id="userDao" class="dao.impl.UserDaoImpl"></bean>
public class UserDaoImpl implements UserDao {

	@Override
	public void save() {
		System.out.println("dao中保存用户的方法执行了。。。");
	}

}

⑤ 测试方法

public void test02(){
	ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
	UserDao userDao = (UserDao) applicationContext.getBean("userDao");
	userDao.save();
}

7.2 Spring注解详解

7.2.1 Component 组件

  • 修饰一个类,将这个类交给Spring管理,这个注解有三个衍生注解:
    • Controller:web层
    • Service:service层
    • Repository:dao层
    • 这三个注解可以代替Component

7.2.2 属性注入的注解

@Value:设置普通属性的值

  • 如果属性有set方法,则将注解添加在set方法上方
@Component("userDao")
public class UserDaoImpl implements UserDao {

	private String name;
	
	@Value("王东") //默认初始值 王东
	public void setName(String name){
		this.name = name;
	}
	@Override
	public void save() {
		System.out.println("dao中保存用户的方法执行了。。。"+name);
	}

}
  • 没有set方法的话注解加在属性上方
@Component("userDao")
public class UserDaoImpl implements UserDao {

	@Value("王东") //默认初始值 王东
	private String name;
	

/*	public void setName(String name){
		this.name = name;
	}*/
	@Override
	public void save() {
		System.out.println("dao中保存用户的方法执行了。。。"+name);
	}

}

@Autowired:设置对象类型的值,默认是按类型完成属性注入。

                       实际开发需要按名称完成属性注入,在属性上方使用@Autowired和@Qualifier。

  • 按类型注入案例:

编写serivce接口及其实现类

public interface UserService {
	public void save();
}
@Service("userService")
public class UserServiceImpl implements UserService {

	@Autowired
	private UserDao userDao;
	@Override
	public void save() {
		System.out.println("userService方法执行了。。。");
		userDao.save();
	}

}

此时为userDao属性赋值时将无视 UserDaoImpl 上方注解名称中的值,因为是按类型注值

  • 按名称注入案例:@Qualifier和@Repository中的值要一致
@Service("userService")
public class UserServiceImpl implements UserService {

	@Autowired
	@Qualifier("userDao")
	private UserDao userDao;
	@Override
	public void save() {
		System.out.println("userService方法执行了。。。");
		userDao.save();
	}

}
@Repository("userDao")
public class UserDaoImpl implements UserDao {

	@Value("王东") //默认初始值 王东
	private String name;
	
	@Override
	public void save() {
		System.out.println("dao中保存用户的方法执行了。。。"+name);
	}

}

@Resource:实现对象属性的按名称注入功能,用来代替@Autowired和@Qualifier,注意该注解中的name值

@Service("userService")
public class UserServiceImpl implements UserService {

	@Resource(name = "userDao")
	private UserDao userDao;
	@Override
	public void save() {
		System.out.println("userService方法执行了。。。");
		userDao.save();
	}

}

7.2.3 其它注解

  • 生命周期相关注解

@PostConstruct 初始化注解

@PreDestroy 销毁方法

@Service("customerService")
public class CustomerServiceImpl implements CustomerService {

	@PostConstruct  //相当于 <bean id="" class="" init-method="setup" destroy-method="destroy"/> 
	public void init(){
		System.out.println("customerService被初始化了!");
	}
	@Override
	public void save() {
		System.out.println("customerService的save方法保存了!");
	}
	@PreDestroy  //相当于 <bean id="" class="" init-method="setup" destroy-method="destroy"/> 
	public void destory(){
		System.out.println("customerService被销毁了!");
	}
	
}
  • Bean作用范围的注解

@Scope

7.3 IOC的XML和注解开发比较

7.4 XML和注解的整合开发

  • xml管理bean,注解完成属性注入

①编写接口及实现类

public interface OrderDao {
	public void save();
}

public class OrderDaoImpl implements OrderDao {

	@Override
	public void save() {
		System.out.println("OrderDao的save方法执行了。。。");
	}

}
public interface ProductDao {
	public void save();
}

public class ProductDaoImpl implements ProductDao {

	@Override
	public void save() {
		System.out.println("ProductDao的save方法执行了。。。");
	}

}
public interface ProductService {
	public void save();
}

public class ProductServiceImpl implements ProductService {
	
	@Resource(name = "productDao")
	private ProductDao productDao;
	@Resource(name = "orderDao")
	private OrderDao orderDao;
    /** 使用@resource可以不用set方法
	public void setProductDao(ProductDao productDao) {
		this.productDao = productDao;
	}

	public void setOrderDao(OrderDao orderDao) {
		this.orderDao = orderDao;
	}
	*/
	@Override
	public void save() {
		productDao.save();
		orderDao.save();
		System.out.println("ProductService的save方法执行了。。。");
	}

}

②配置xml文件,将类交给spring管理

<?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">

	<!-- 指定扫描dao包下的所有类中的注解.注意:扫描包时.会扫描指定包下的所有子孙包 -->
	<!-- <context:component-scan base-package="spring"></context:component-scan> -->
	<!-- 由于bean是通过xml配置的,所以无需开启类注解扫描,只需开启属性注解扫描 -->
	<context:annotation-config></context:annotation-config>
	<bean id="productDao" class="spring.dao.impl.ProductDaoImpl"></bean>
	<bean id="orderDao" class="spring.dao.impl.OrderDaoImpl"></bean>
	<bean id="productService" class="spring.service.impl.ProductServiceImpl"></bean>
</beans>

 

八.Spring分模块开发与项目优化

8.1 引入配置文件

在applicationContext.xml中引入其他配置文件

	<import resource="applicationContext2.xml"/>	

8.2 Spring项目优化

8.2.1 问题:

每次请求都会创建一个Spring的工厂,这样浪费服务器资源,应该一个项目只有一个Spring的工厂。

8.2.2 解决方案:

  • 在服务器启动的时候,创建一个Spring的工厂,创建完工厂,将这个工厂类保存到ServletContext中,每次使用的时候都从ServletContext中获取,使用ServletContextListener,监听ServletContext对象的创建和销毁。
  • 引入jar包:spring-web.jar
  • 配置监听器

  • 在Action中获取工厂

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值