代码通过getbean();方式从容器中获取指定的bean实例,容器首先会调用bean类的无参构造器,创建空值的实例对象。
举例:
首先我在applicationContext.xml配置文件中配置了一个bean:
1 2 3 |
|
创建SomeServiceImpl对象,但需要注意的是该类的只具有带参构造函器,没有无参构造器:
1 2 3 4 5 6 7 8 9 10 11 |
|
测试:
1 2 3 4 5 |
|
此时程序会报以下的错误:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
|
解析:这里的错误报的很明显,没有发现默认的构造器。
修改:为该类加上无参构造器:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
此时,再次运行测试用例,会发现运行成功。
结论:Spring容器实际上是使用了类的反射机制,会首先调用Bean类的无参构造器创建实例对象。
创建SomeServiceImpl类:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
创建工厂类ServiceFactory:
1 2 3 4 5 6 7 |
|
使用动态工厂方式获取Bean对象,配置如下:
1 2 3 |
|
在这里并没有注册SomeServiceImpl类,而是通过ServiceFactory工厂的getSomeService方法获取的。
测试:
1 2 3 4 5 6 |
|
运行成功。
静态工厂和动态工厂不同的是,静态工厂中使用的是静态方法创建对象,如:
1 2 3 4 5 6 7 |
|
对应的配置文件修改如下:
1 2 3 |
|
测试:
1 2 3 4 5 6 |
|
成功创建SomeServiceImpl对象。
Bean的作用域(scope)分为四种,分别是singleton、prototype、request、session。
scope:
singleton(默认):单例模式,其对象的创建时机是在Spring容器初始化时创建,是默认值
prototype:原型模式,其对象的创建时机不是在Spring容器初始化时创建,而是在代码中真正访问时才创建,每次使用getBean方法获取的同一个
request:对于每次HTTP请求,都将会产生一个不同的Bean实例
session:对于每个不同的HTTP session,都将会产生一个不同的Bean实例
验证:
首先配置作用域为singleton:
1 |
|
测试:
1 2 3 4 5 6 7 8 |
|
程序输出:
1 2 |
|
结论:当作用域为singleton单例模式时,只会创建一个对象实例,并且对象是在Spring容器初始化时创建。
同样,当配置为prototype原型模式时:
1 |
|
程序输出:
1 2 3 |
|
结论:构造器被调用了两次,说明创建的service1和service2不是同一个对象,并且对象是在被使用到时才创建的。
Bean后处理器是一种特殊的Bean,容器中所有的Bean在初始化时,均会自动执行该类的两个方法。由于该Bean是由其它Bean自动调用执行,不是程序员手工调用,故此Bean无须id属性。
需要做的是,在Bean后处理器类方法中,只要对Bean类与Bean类中的方法进行判断,就可实现对指定的Bean的指定的方法进行功能扩展与增强。方法返回的Bean对象,即是增强过的对象。
代码中需要自定义Bean后处理器类,该类就是实现了接口BeanPostProcessor的类。该接口中包含两个方法,分别在目标Bean初始化完毕之前与之后执行,它的返回值为功能被扩展或增强后的Bean对象。
举例:利用Bean后处理器实现大小写字符串转换
接口类ISomeService:
1 2 3 4 5 6 7 8 |
|
实现类SomeServiceImpl:
1 2 3 4 5 6 7 8 |
|
定义Bean处理器MyBeanPostProcessor:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
使用JDK动态代理实现大小写转换的功能。
配置文件:
1 |
|
注意:Bean后处理器不需要配置id的,因为它是随着对象的创建自动调用的。
测试:
1 2 3 4 5 6 7 8 |
|
程序输出:
1 2 |
|
增强成功。可以判断代理类的类型,进行对单个或单独一类对象做增强。
Bean实例从创建到最后销毁,需要经过很多过程,执行很多生命周期方法。
Step1:调用无参构造器,创建实例对象。
Step2:调用参数的setter,为属性注入值。
Step3:若Bean实现了BeanNameAware接口,则会执行接口方法setBeanName(String beanId),使Bean类可以获取其在容器中的id名称。
Step4:若Bean实现了BeanFactoryAware接口,则执行接口方法setBeanFactory(BeanFactory factory),使Bean类可以获取到BeanFactory对象。
Step5:若定义并注册了Bean后处理器BeanPostProcessor,则执行接口方法postProcessBeforeInitialization()。
Step6:若Bean实现了InitializingBean接口,则执行接口方法afterPropertiesSet()方法。该方法在Bean的所有属性的set方法执行完毕后执行,是Bean初始化结束的标志,即Bean实例化结束。
Step7:若设置了init-method方法,则执行。
Step8:若定义并注册了Bean后处理器BeanPostProcessor,则执行接口方法postProcessAfterInitialization().
Step9:执行业务方法。
Step10:若Bean实现了DisposableBean接口,则执行接口方法destroy()。
Step11:若设置了destroy-method方法,则执行。
举例:
创建接口类ISomeService:
1 2 3 4 5 6 |
|
创建接口实现类SomeServiceImpl:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
创建BeanPostProcessor接口的实现类MyBeanPostProcessor:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
配置applicationContext.xml文件:
1 2 3 |
|
测试类:
1 2 3 4 5 6 7 8 |
|
程序输出:
1 2 3 4 5 6 7 8 9 10 |
|
正如程序输出的序列一样,此顺序即是对象创建的调用顺序,在编程中可以在某一个过程对其进行增强操作。
一般情况下,命名
id的命名需要满足XML对ID属性命名规范:必须以字母开头,可以包含字母、数字、下划线、连字符、句号、冒号。
name属性值可以包含各种字符。
以上就是Spring框架第二篇之Bean的装配的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号