经过反射调用构造方法建立bean对象java
经过静态工厂方法建立bean对象算法
经过实例工厂方法建立bean对象spring
经过FactoryBean建立bean对象数据库
Spring容器内部建立bean实例对象常见的有4种方式。缓存
调用类的构造方法获取对应的bean实例,是使用最多的方式,这种方式只须要在xml bean元素中指定class属性,spring容器内部会自动调用该类型的构造方法来建立bean对象,将其放在容器中以供使用。并发
<bean id="bean名称" name="bean名称或者别名" class="bean的完整类型名称"> <constructor-arg index="0" value="bean的值" ref="引用的bean名称" /> <constructor-arg index="1" value="bean的值" ref="引用的bean名称" /> <constructor-arg index="2" value="bean的值" ref="引用的bean名称" /> .... <constructor-arg index="n" value="bean的值" ref="引用的bean名称" /> </bean>
constructor-arg用于指定构造方法参数的值less
index:构造方法中参数的位置,从0开始,依次递增ide
value:指定参数的值函数
ref:当插入的值为容器内其余bean的时候,这个值为容器中对应bean的名称高并发
@Getter @Setter @ToString public class UserModel { private String name; private int age; public UserModel() { this.name = "我是经过UserModel的无参构造方法建立的!"; } public UserModel(String name, int age) { this.name = name; this.age = age; } }
<!-- 经过UserModel的默认构造方法建立UserModel对象 --> <bean id="createBeanByConstructor1" class="com.javacode2018.lesson001.demo3.UserModel"/> <!-- 经过UserModel有参构造方法建立UserModel对象 --> <bean id="createBeanByConstructor2" class="com.javacode2018.lesson001.demo3.UserModel"> <constructor-arg index="0" value="我是经过UserModel的有参方法构造的对象!"/> <constructor-arg index="1" value="30"/> </bean>
上面这2种写法,spring容器建立这两个UserModel的时候,都会经过反射的方式去调用UserModel类中对应的构造函数来建立UserModel对象。
package com.javacode2018.lesson001.demo3; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.net.URL; import java.net.URLClassLoader; import java.util.Arrays; /** * 公众号:路人甲Java,工做10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活! */ public class Client { public static void main(String[] args) { //1.bean配置文件位置 String beanXml = "classpath:/com/javacode2018/lesson001/demo3/beans.xml"; //2.建立ClassPathXmlApplicationContext容器,给容器指定须要加载的bean配置文件 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(beanXml); System.out.println("spring容器中全部bean以下:"); //getBeanDefinitionNames用于获取容器中全部bean的名称 for (String beanName : context.getBeanDefinitionNames()) { System.out.println(beanName + ":" + context.getBean(beanName)); } } }
代码中会输出spring容器中全部bean的名称和其对应的bean对象。
spring容器中全部bean以下: createBeanByConstructor1:UserModel(name=我是经过UserModel的无参构造方法建立的!, age=0) createBeanByConstructor2:UserModel(name=我是经过UserModel的有参方法构造的对象!, age=30)
咱们能够建立静态工厂,内部提供一些静态方法来生成所须要的对象,将这些静态方法建立的对象交给spring以供使用。
<bean id="bean名称" name="" class="静态工厂完整类名" factory-method="静态工厂的方法"> <constructor-arg index="0" value="bean的值" ref="引用的bean名称" /> <constructor-arg index="1" value="bean的值" ref="引用的bean名称" /> <constructor-arg index="2" value="bean的值" ref="引用的bean名称" /> .... <constructor-arg index="n" value="bean的值" ref="引用的bean名称" /> </bean>
class:指定静态工厂完整的类名
factory-method:静态工厂中的静态方法,返回须要的对象。
constructor-arg用于指定静态方法参数的值,用法和上面介绍的构造方法同样。
spring容器会自动调用静态工厂的静态方法获取指定的对象,将其放在容器中以供使用。
建立一个静态工厂类,用于生成UserModel对象。
package com.javacode2018.lesson001.demo3; /** * 公众号:路人甲Java,工做10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活! */ public class UserStaticFactory { /** * 静态无参方法建立UserModel * * @return */ public static UserModel buildUser1() { System.out.println(UserStaticFactory.class + ".buildUser1()"); UserModel userModel = new UserModel(); userModel.setName("我是无参静态构造方法建立的!"); return userModel; } /** * 静态有参方法建立UserModel * * @param name 名称 * @param age 年龄 * @return */ public static UserModel buildUser2(String name, int age) { System.out.println(UserStaticFactory.class + ".buildUser2()"); UserModel userModel = new UserModel(); userModel.setName(name); userModel.setAge(age); return userModel; } }
<!-- 经过工厂静态无参方法建立bean对象 --> <bean id="createBeanByStaticFactoryMethod1" class="com.javacode2018.lesson001.demo3.UserStaticFactory" factory-method="buildUser1"/> <!-- 经过工厂静态有参方法建立bean对象 --> <bean id="createBeanByStaticFactoryMethod2" class="com.javacode2018.lesson001.demo3.UserStaticFactory" factory-method="buildUser2"> <constructor-arg index="0" value="经过工厂静态有参方法建立UerModel实例对象"/> <constructor-arg index="1" value="30"/> </bean>
上面配置中,spring容器启动的时候会自动调用UserStaticFactory中的buildUser1静态方法获取UserModel对象,将其做为createBeanByStaticFactoryMethod1名称对应的bean对象放在spring容器中。
会调用UserStaticFactory的buildUser2方法,而且会传入2个指定的参数,获得返回的UserModel对象,将其做为createBeanByStaticFactoryMethod2名称对应的bean对象放在spring容器中。
class com.javacode2018.lesson001.demo3.UserStaticFactory.buildUser1() class com.javacode2018.lesson001.demo3.UserStaticFactory.buildUser2() spring容器中全部bean以下: createBeanByStaticFactoryMethod1:UserModel(name=我是无参静态构造方法建立的!, age=0) createBeanByStaticFactoryMethod2:UserModel(name=经过工厂静态有参方法建立UerModel实例对象, age=30)
从输出中能够看出,两个静态方法都被调用了,createBeanByStaticFactoryMethod1对应的bean对象是经过buildUser1方法建立的;createBeanByStaticFactoryMethod2对应的bean对象是经过buildUser2方法建立的。
让spring容器去调用某些对象的某些实例方法来生成bean对象放在容器中以供使用。
<bean id="bean名称" factory-bean="须要调用的实例对象bean名称" factory-method="bean对象中的方法"> <constructor-arg index="0" value="bean的值" ref="引用的bean名称" /> <constructor-arg index="1" value="bean的值" ref="引用的bean名称" /> <constructor-arg index="2" value="bean的值" ref="引用的bean名称" /> .... <constructor-arg index="n" value="bean的值" ref="引用的bean名称" /> </bean>
spring容器以factory-bean的值为bean名称查找对应的bean对象,而后调用该对象中factory-method属性值指定的方法,将这个方法返回的对象做为当前bean对象放在容器中供使用。
内部写2个方法用来建立UserModel对象。
package com.javacode2018.lesson001.demo3; /** * 公众号:路人甲Java,工做10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活! */ public class UserFactory { public UserModel buildUser1() { System.out.println("----------------------1"); UserModel userModel = new UserModel(); userModel.setName("bean实例方法建立的对象!"); return userModel; } public UserModel buildUser2(String name, int age) { System.out.println("----------------------2"); UserModel userModel = new UserModel(); userModel.setName(name); userModel.setAge(age); return userModel; } }
<!-- 定义一个工厂实例 --> <bean id="userFactory" class="com.javacode2018.lesson001.demo3.UserFactory"/> <!-- 经过userFactory实例的无参user方法建立UserModel对象 --> <bean id="createBeanByBeanMethod1" factory-bean="userFactory" factory-method="buildUser1"/> <!-- 经过userFactory实例的有参user方法建立UserModel对象 --> <bean id="createBeanByBeanMethod2" factory-bean="userFactory" factory-method="buildUser2"> <constructor-arg index="0" value="经过bean实例有参方法建立UserModel实例对象"/> <constructor-arg index="1" value="30"/> </bean>
createBeanByBeanMethod1对应的bean是经过userFactory的buildUser1方法生成的。
createBeanByBeanMethod2对应的bean是经过userFactory的buildUser2方法生成的。
spring容器中全部bean以下: createBeanByBeanMethod1:UserModel(name=bean实例方法建立的对象!, age=0) createBeanByBeanMethod2:UserModel(name=经过bean实例有参方法建立UserModel实例对象, age=30)
前面咱们学过了BeanFactory接口,BeanFactory是spring容器的顶层接口,而这里要说的是FactoryBean,也是一个接口,这两个接口很容易搞混淆,FactoryBean可让spring容器经过这个接口的实现来建立咱们须要的bean对象。
FactoryBean接口源码:
public interface FactoryBean<T> { /** * 返回建立好的对象 */ @Nullable T getObject() throws Exception; /** * 返回须要建立的对象的类型 */ @Nullable Class<?> getObjectType(); /** * bean是不是单例的 **/ default boolean isSingleton() { return true; } }
接口中有3个方法,前面2个方法须要咱们去实现,getObject方法内部由开发者本身去实现对象的建立,而后将建立好的对象返回给Spring容器,getObjectType须要指定咱们建立的bean的类型;最后一个方法isSingleton表示经过这个接口建立的对象是不是单例的,若是返回false,那么每次从容器中获取对象的时候都会调用这个接口的getObject() 去生成bean对象。
<bean id="bean名称" class="FactoryBean接口实现类" />
package com.javacode2018.lesson001.demo3; import org.springframework.beans.factory.FactoryBean; import org.springframework.lang.Nullable; /** * 公众号:路人甲Java,工做10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活! */ public class UserFactoryBean implements FactoryBean<UserModel> { int count = 1; @Nullable @Override public UserModel getObject() throws Exception { //@1 UserModel userModel = new UserModel(); userModel.setName("我是经过FactoryBean建立的第"+count+++ "对象");//@4 return userModel; } @Nullable @Override public Class<?> getObjectType() { return UserModel.class; //@2 } @Override public boolean isSingleton() { return true; //@3 } }
@1:返回了一个建立好的UserModel对象
@2:返回对象的Class对象
@3:返回true,表示建立的对象是单例的,那么咱们每次从容器中获取这个对象的时候都是同一个对象
@4:此处用到了一个count,经过这个一会能够看出isSingleton不一样返回值的时候从容器获取的bean是不是同一个
<!-- 经过FactoryBean 建立UserModel对象 --> <bean id="createByFactoryBean" class="com.javacode2018.lesson001.demo3.UserFactoryBean"/>
package com.javacode2018.lesson001.demo3; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.net.URL; import java.net.URLClassLoader; import java.util.Arrays; /** * 公众号:路人甲Java,工做10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活! */ public class Client { public static void main(String[] args) { //1.bean配置文件位置 String beanXml = "classpath:/com/javacode2018/lesson001/demo3/beans.xml"; //2.建立ClassPathXmlApplicationContext容器,给容器指定须要加载的bean配置文件 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(beanXml); System.out.println("spring容器中全部bean以下:"); //getBeanDefinitionNames用于获取容器中全部bean的名称 for (String beanName : context.getBeanDefinitionNames()) { System.out.println(beanName + ":" + context.getBean(beanName)); } System.out.println("--------------------------"); //屡次获取createByFactoryBean看看是不是同一个对象 System.out.println("createByFactoryBean:" + context.getBean("createByFactoryBean")); System.out.println("createByFactoryBean:" + context.getBean("createByFactoryBean")); } }
运行输出
class com.javacode2018.lesson001.demo3.UserStaticFactory.buildUser1() class com.javacode2018.lesson001.demo3.UserStaticFactory.buildUser2() ----------------------1 ----------------------2 spring容器中全部bean以下: createBeanByConstructor1:UserModel(name=我是经过UserModel的无参构造方法建立的!, age=0) createBeanByConstructor2:UserModel(name=我是经过UserModel的有参方法构造的对象!, age=30) createBeanByStaticFactoryMethod1:UserModel(name=我是无参静态构造方法建立的!, age=0) createBeanByStaticFactoryMethod2:UserModel(name=经过工厂静态有参方法建立UerModel实例对象, age=30) userFactory:com.javacode2018.lesson001.demo3.UserFactory@610694f1 createBeanByBeanMethod1:UserModel(name=bean实例方法建立的对象!, age=0) createBeanByBeanMethod2:UserModel(name=经过bean实例有参方法建立UserModel实例对象, age=30) createByFactoryBean:UserModel(name=我是经过FactoryBean建立的第1对象, age=0) -------------------------- createByFactoryBean:UserModel(name=我是经过FactoryBean建立的第1对象, age=0) createByFactoryBean:UserModel(name=我是经过FactoryBean建立的第1对象, age=0)
注意最后4行输出,有3行输出的都是同一个createByFactoryBean,程序中经过getBean从spring容器中查找createByFactoryBean了3次,3次结果都是同样的,说明返回的都是同一个UserModel对象。
下面咱们将UserFactoryBean中的isSingleton调整一下,返回false
@Override public boolean isSingleton() { return false; }
当这个方法返回false的时候,表示由这个FactoryBean建立的对象是多例的,那么咱们每次从容器中getBean的时候都会去从新调用FactoryBean中的getObject方法获取一个新的对象。
再运行一下Client,最后4行输出:
createByFactoryBean:UserModel(name=我是经过FactoryBean建立的第1对象, age=0) -------------------------- createByFactoryBean:UserModel(name=我是经过FactoryBean建立的第2对象, age=0) createByFactoryBean:UserModel(name=我是经过FactoryBean建立的第3对象, age=0)
这3次获取的对象不同了。
spring容器提供了4种建立bean实例的方式,除了构造函数的方式,其余几种方式可让咱们手动去控制对象的建立,这几种方式你们都掌握一下,可以灵活使用。
连接:https://pan.baidu.com/s/1p6rcfKOeWQIVkuhVybzZmQ 提取码:zr99
感谢你们的阅读,也欢迎您把这篇文章分享给更多的朋友一块儿阅读!谢谢!
路人甲java
▲长按图片识别二维码关注
路人甲Java:工做10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活!