JVM–10–创建对象的步骤、对象实例化内存布局、访问定位
在学习Spring的时候,发现Spring的IOC(控制反转)为我们提供的三种创建Bean的方式。
User.java
public class User {
private int id;
private String name;
public User() {
super();
System.out.println("------User对象创建【无参数构造器】------");
}
public User(int id, String name) {
System.out.println("-----User对象创建【带参数构造器】--------");
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + "]";
}
}
Bean.xml配置如下:
<!-- 1. 默认无参数构造器 -->
<bean id="user1" class="com.nwpu.geeker.User"></bean>
测试:
// 测试:对象创建
@Test
public void testIOC() throws Exception {
// 创建IOC容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("com/nwpu/geeker/bean.xml");
// 获取容器中的对象
User user = (User) ac.getBean("user");
System.out.println(user);
}
例如:上面的user.java 有带参的构造器,参数列表为(int,string).一般依赖注入对象的时候用的比较多。
配置如下:
<!-- 2. 带参数构造器 -->
<bean id="user2" class="com.nwpu.geeker..User">
<constructor-arg index="0" type="int" value="100"></constructor-arg>
<constructor-arg index="1" type="java.lang.String" value="Jack"></constructor-arg>
</bean>
其中index属性表示参数的位置。Type表示类型,value表示赋值,还有一个ref属性下面将会介绍,表示可以引用IOC容器创建好的(已存在的)对象。
配置如下:
<!-- 定义一个字符串,值是"Jack" ; String s = new String("jack")-->
<bean id="str" class="java.lang.String">
<constructor-arg value="Jacks"></constructor-arg>
</bean>
<bean id="user3" class="com.nwpu.geeker.User">
<constructor-arg index="0" type="int" value="100"></constructor-arg>
<constructor-arg index="1" type="java.lang.String" ref="str"></constructor-arg>
</bean>
1
ref属性引用的就是IOC容器创建对象的id属性值。
public class UserFactory {
// 静态方法
public static User getUser1() {
return new User();
}
}
<!-- 使用静态工厂创建user -->
<bean id="user1" class="ioc.service.UserFactory" factory-method="getUser1"></bean>
class 指的是该工厂类的包路径,factory-method 指的是该工厂类创建Bean的静态方法。注意:这里一定要静态方法
@Test
public void testUser1(){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
// 静态工厂创建
User user1 = (User) context.getBean("user1");
System.out.println("静态工厂创建:" + user1);
}
这里 context 是指 new 出来 spring bean 工厂对象,根据编辑好的配置文件 .xml 实例化出来的
public class UserFactory {
//普通方法
public User getUser2() {
return new User();
}
}
<!-- 使用实例工厂创建 user -->
<bean id="userFactory" class="ioc.service.UserFactory"></bean>
<bean id="user2" factory-bean="userFactory" factory-method="getUser2"></bean>
@Test
public void testUser2(){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
// 实例工厂创建
User user2 = (User) context.getBean("user2");
System.out.println("实例工厂创建:" + user2);
}
1.先创建springbean工厂对象
2.再创建UserFactory对象,
3.再调用UserFactory对象中的getUser2()方法, 返回User对象
这三种方式最根本的区别还是创建方式的不同。
第一种,通过默认的无参构造方式创建,其本质就是把类交给Spring自带的工厂(BeanFactory)管理、由Spring自带的工厂模式帮我们维护和创建这个类。如果是有参的构造方法,也可以通过XML配置传入相应的初始化参数,这种也是开发中用的最多的。
第二种,通过静态工厂创建,其本质就是把类交给我们自己的静态工厂管理,Spring只是帮我们调用了静态工厂创建实例的方法,而创建实例的这个过程是由我们自己的静态工厂实现的,
在实际开发的过程中,很多时候我们需要使用到第三方jar包提供给我们的类,而这个类没有构造方法,而是通过第三方包提供的静态工厂创建的,这是时候,如果我们想把第三方jar里面的这个类交由spring来管理的话,就可以使用Spring提供的静态工厂创建实例的配置。
第三种,通过实例工厂创建,其本质就是把创建实例的工厂类交由Spring管理,同时把调用工厂类的方法创建实例的这个过程也交由Spring管理,看创建实例的这个过程也是有我们自己配置的实例工厂内部实现的。在实际开发的过程中,如Spring整合Hibernate就是通过这种方式实现的。但对于没有与Spring整合过的工厂类,我们一般都是自己用代码来管理的。