前言:
此时同学们对“java官方文档如何阅读”都比较关心,我们都想要了解一些“java官方文档如何阅读”的相关文章。那么小编同时在网摘上收集了一些对于“java官方文档如何阅读””的相关内容,希望兄弟们能喜欢,姐妹们一起来学习一下吧!1.4.4. Lazy-initialized Beans
<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/><bean name="not.lazy" class="com.something.AnotherBean"/>
通过设定lazy-init属性来表示是否懒加载,同时,如果该bean是其他bean的dependency,依然会直接加载出来。
1.4.6. Method Injection
搞了半天终于知道这个东西是什么意思了,考虑这样一个情况,由于bean在容器中很多时候都是单例的,所以我们会一直用同一个对象。但是某些情况下,我们需要每次都拿到一个新的对象,这个时候就可以考虑重写Aware方法。
举个例子,我们有一个Command对象,现在我们每次需要一个新的Command,很明显,当我们要将这个bean注入context的时候,scope要填prototype(意思是每次取就创建一个新的,区别于Singleton)。
<bean id="command" class="edu.csu.example.demo.methodinjection.Command" scope="prototype"/><bean id="commandManager" class="edu.csu.example.demo.methodinjection.CommandManager"/>
package edu.csu.example.demo.methodinjection;public class Command { public Object execute() { System.out.println("命令已执行"); return "end"; }}
很自然的,我们第一个想到的方式是通过容器进行注入,将command注入到commandManager中
<bean id="commandManager" class="edu.csu.example.demo.methodinjection.CommandManager"> <property name="command" ref="command"/></bean>
由于command是prototype,理论上每次注入都应该是一个新的对象:
public class CommandManager implements ApplicationContextAware { private ApplicationContext applicationContext; private Command command; // inject public void setCommand(Command command) { this.command = command; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } public Object process(Map commandState) { // grab a new instance of the appropriate Command System.out.println(command); // set the state on the (hopefully brand new) Command instance return command.execute(); }}
进行测试:
System.out.println("------------------Method Injection------------------------"); CommandManager cm = context.getBean("commandManager", CommandManager.class); Map<String, String> commandState = new HashMap<>(); cm.process(commandState); cm.process(commandState);
结果:
可以看到,还是同一个元素,这与我们一开始写的prototype是相违背的。
现在我们用method injection的方式,方法很简单,虽然通过setter注入进去的对象是同一个,但是通过context.get出来的一定不同,我们通过实现ApplicationContextAware接口来直接从容器中获取对象:
public class CommandManager implements ApplicationContextAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } public Object process(Map commandState) { // grab a new instance of the appropriate Command Command command = createCommand(); System.out.println(command); // set the state on the (hopefully brand new) Command instance return command.execute(); } protected Command createCommand() { // notice the Spring API dependency! return this.applicationContext.getBean("command", Command.class); }}
注意删除property
结果:
当然,这种方法看上去好像直接对context进行了操作,不是很好,所以spring提供了另外一个方式来做这个事情:
我们通过将commandManager设为抽象类,且createCommand设为抽象方法,同时我们在注入bean的时候加入lookup-method标签来指定当我们调用method时,返回那个bean:
<bean id="command" class="edu.csu.example.demo.methodinjection.Command" scope="prototype"/><bean id="commandManager" class="edu.csu.example.demo.methodinjection.CommandManager"> <lookup-method name="createCommand" bean="command"/></bean>
public abstract class CommandManager implements ApplicationContextAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } public Object process(Map commandState) { // grab a new instance of the appropriate Command Command command = createCommand(); System.out.println(command); // set the state on the (hopefully brand new) Command instance return command.execute(); } protected abstract Command createCommand();}
结果:
值得注意的是,我们没有在任何地方实现createCommand这个抽象方法。
Arbitrary Method Replacement
我们甚至能够替换类中的某个函数的实现,xml中通过replaced-method这个tag来进行实现:
package edu.csu.example.demo.methodinjection;public class MyValueCalculator { public String computeValue(String input) { System.out.println("original: this input is:" + input); return "this is original method"; }}
新建一个类,重写这个方法,但是并不是继承:
package edu.csu.example.demo.methodinjection;import java.lang.reflect.Method;public class ReplacementComputeValue { public Object reimplement(Object o, Method m, Object[] args) throws Throwable { // get the input value, work with it, and return a computed result String input = (String) args[0]; System.out.println("replaced: this input is:" + input); return "this is replaced method"; }}
然后我们在xml中进行替换:
<bean id="myValueCalculator" class="edu.csu.example.demo.methodinjection.MyValueCalculator"> <!-- arbitrary method replacement --> <replaced-method name="computeValue" replacer="replacementComputeValue"> <arg-type>String</arg-type> </replaced-method></bean><bean id="replacementComputeValue" class="edu.csu.example.demo.methodinjection.ReplacementComputeValue"/>
执行结果:
1.5. Bean Scopes
spring中一切bean都是通过容器控制的,所以容器同样可以控制其生命周期,常见的生命周期有:singleton、prototype、request、session、application、websocket
The Singleton Scope:每次用到该对象时,容器都会返回同一个对象
The Prototype Scope:每次用到该对象时,容器都会返回一个新的对象
注意,如果singleton的bean A中引用了prototype的bean B,并且要求每次创建A时都新建一个B,这种情况是不能直接进行引用,要想实现这样的效果,参考上面的method-injection
Scoped Beans as Dependencies
对于有scope的bean作为注入对象,如果需要延长bean的生命周期,需要进行proxy来进行代理调用(这里有点不理解,哪怕是代理,bean销毁了应该也调用不了了,感到奇怪)
1.5.5. Custom Scopes:见文档,感觉很 很复杂,用得到再说吧
Scope (Spring Framework 5.2.1.RELEASE API)docs.spring.io
1.6. Customizing the Nature of a Bean
重要,bean的生命周期调用
1.6.1. Lifecycle Callbacks
官方不建议使用InitializingBean(会增加code和spring之间不必要的耦合),而更加提倡:init-method和@PostConstruct
<bean id="exampleInitBean" class="edu.csu.example.demo.lifecycle.ExampleBean" init-method="init"/>
package edu.csu.example.demo.lifecycle;public class ExampleBean { public void init() { System.out.println("this is initial func"); }}
输出结果:
可以知道调用了init func
Startup and Shutdown Callbacks
在管理bean的过程中,管理bean的类实现了三个生命周期function
public interface Lifecycle { void start(); void stop(); boolean isRunning();}
当applicationcontext收到相应信号时就会调用相应的func
public interface LifecycleProcessor extends Lifecycle { void onRefresh(); void onClose();}
LifecycleProcessor新增了两个生命周期
在某些情况下,我们的某个bean是需要依赖其他的bean的(例如depends-on),所以对bean的初始化顺序也有一定的要求,在这里,我们可以通过smartLifecycle这个接口来对初始化顺序进行管理:
public interface Phased { int getPhase();}
public interface SmartLifecycle extends Lifecycle, Phased { boolean isAutoStartup(); void stop(Runnable callback);}
可以看到,SmartLifecycle接口有两个父接口,其中一个是Lifecycle,第二个是phased,对于第二个接口来说,可以通过具体的实现来控制bean的初始化顺序,大体来说phase越小初始化得越早。
1.6.2. ApplicationContextAware and BeanNameAware
有的时候我们需要通过applicationContext来进行一些必要的操作,这时我们需要拿到applicationContext这个对象,实现方式有两种
1:实现ApplicationContextAware这个接口
public interface ApplicationContextAware { void setApplicationContext(ApplicationContext applicationContext) throws BeansException;}
实现了这个接口之后,spring容器在初始化时就会将上下文注入进去,这样就能拿到上下文对象了。
2:通过autowire
autowire可以将applicationContext以参数的形式给到构造函数和setter函数中的参数当中,这样就能够拿到上下文对象了。
public interface BeanNameAware { void setBeanName(String name) throws BeansException;}
这个接口会在set完properties后调用,嗯。
1.6.3. Other Aware Interfaces
忒多了,截个图吧,有需要再看:
本文出自知乎
更多相关内容,Java架构师,软件开发等学习资料,电子书及视频还有高级讲师公开课免费资源
需要的可以私聊小编发送【学习】二字
标签: #java官方文档如何阅读