Spring 的依赖注入容器的核心是 Beanfactory 接口。 Beanfactory 负责管理组件,包括依赖项以及它们的生命周 期
public interface Oracle { String defineMeaningOfLife () ;}
public class BookwormOracle implements Oracle {
@Override
public String defineMeaningOfLife() {
return "go see the world instead";
}
}
xml-bean-factory-config.xml
<?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">
<bean id="oracle" name="wiseworm" class="com.anocation.spring5.ch3.BookwormOracle"/>
</beans>
public class XmlConfigWithBeanFactory {
public static void main(String[] args) {
DefaultListableBeanFactory factory= new DefaultListableBeanFactory();
XmlBeanDefinitionReader rdr =new XmlBeanDefinitionReader(factory);
rdr.loadBeanDefinitions(new ClassPathResource("xml-bean-factory-config.xml"));
Oracle oracle = factory.getBean("oracle", Oracle.class);
System.out.println(oracle.defineMeaningOfLife());
}
}
app-context-xml.xml
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="provider" class="com.anocation.spring5.ch3.annotation.HelloWorldMessageProvider"/>
<bean id="renderer" class="com.anocation.spring5.ch3.annotation.StandardOutMessageRenderer"
p:messageProvider-ref="provider"/>
</beans>
public class DeclareSpringComponents {
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:app-context-xml.xml");
ctx.refresh();
MessageRenderer messageRenderer = ctx.getBean("renderer", MessageRenderer.class);
messageRenderer.render();
ctx.close();
}
}
@Component("provider")
public class HelloWorldMessageProvider implements MessageProvider {
@Override
public String getMessage() {
return "Hello World!";
}
}
使用@Autowired注入MessageProvider,可以在setter上添加,或使用@Resource
@Service("renderer")
public class StandardOutMessageRenderer implements MessageRenderer {
// @Autowired
private MessageProvider messageProvider;
@Override
public void render() {
if (messageProvider==null){
throw new RuntimeException("you must set the property messageProvider of class:"
+ StandardOutMessageRenderer.class.getName());
}
System.out.println(messageProvider.getMessage());
}
@Override
@Autowired
// @Resource(name = "provider")
public void setMessageProvider(MessageProvider provider) {
this.messageProvider = provider;
}
@Override
public MessageProvider getMessageProvider() {
return this.messageProvider;
}
}
app-context-annotation.xml
<?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">
<context:component-scan base-package="com.anocation.spring5.ch3.annotation"/>
</beans>
public class AnnotationDeclareSpringComponents {
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:app-context-annotation.xml");
ctx.refresh();
MessageRenderer messageRenderer = ctx.getBean("renderer", MessageRenderer.class);
messageRenderer.render();
ctx.close();
}
}
使用GenericXmlApplicationContext而不是DefaultListableBeanFactory的一个实例被实例化。GenericXmlApplicationContext类实现了ApplicationContext接口, 并能够通过XML文件中定义的配置启动Sring的ApplicationContext
@Configuration
public class HelloWorldConfiguration {
@Bean
public MessageProvider provider(){
return new HelloWorldMessageProvider();
}
@Bean
public MessageRenderer renderer(){
MessageRenderer renderer = new StandardOutMessageRenderer();
renderer.setMessageProvider(provider());
return renderer;
}
}
public class HelloWorldSpringAnnotated {
public static void main(String[] args){
ApplicationContext ctx = new AnnotationConfigApplicationContext(HelloWorldConfiguration.class);
MessageRenderer mr = ctx.getBean("renderer", MessageRenderer.class);
mr.render();
}
}
AnnotationConfigApplicationContext类实现了 ApplicationContext接口,并且能够根据 HelloWorldConfiguration类定义 的配置信息启动 Spring 的 ApplicationContext
@ComponentScan(basePackages = "com.anocation.spring5.ch3.annotation")
@Configuration
public class HelloWorldConfiguration {
}
@ImportResource(locations = "classpath:app-context-annotation.xml")
@Configuration
public class HelloWorldConfiguration {
}
/**
* 使用构造函数注入
*/
public class ConfigurableMessageProvider implements MessageProvider{
private String message;
@Autowired
public ConfigurableMessageProvider(@Value("默认值") String message) {
this.message = message;
}
@Override
public String getMessage() {
return message;
}
}
app-context-xml2.xml
<?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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- <bean id="provider" class="com.anocation.spring5.ch3.annotation.ConfigurableMessageProvider">-->
<!-- <constructor-arg value="Hello World!!!"/>-->
<!-- </bean>-->
<bean id="provider" class="com.anocation.spring5.ch3.annotation.ConfigurableMessageProvider"
c:message="Hello World!!!"
/>
</beans>
@ComponentScan(basePackages = "com.anocation.spring5.ch3.annotation")
//@ImportResource(locations = "classpath:app-context-annotation.xml")
@ImportResource(locations = "classpath:app-context-xml2.xml")
@Configuration
public class HelloWorldConfiguration {
}
public class HelloWorldSpringAnnotated {
public static void main(String[] args){
ApplicationContext ctx = new AnnotationConfigApplicationContext(HelloWorldConfiguration.class);
MessageRenderer mr = ctx.getBean("renderer", MessageRenderer.class);
mr.render();
}
}
<?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"
xmlns:c="http://www.springframework.org/schema/c"
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">
<context:component-scan base-package="com.anocation.spring5.ch3.annotation"/>
<!-- 一0表示构造函数参数的索引-->
<bean id="message" class="java.lang.String"
c:_0="Hello World!!!!"/>
</beans>
@Component("provider")
public class ConfigurableMessageProvider implements MessageProvider{
private String message;
// @Autowired
// public ConfigurableMessageProvider(@Value("默认值") String message) {
// this.message = message;
// }
@Autowired
public ConfigurableMessageProvider(String message) {
this.message = message;
}
@Override
public String getMessage() {
return message;
}
}
/**
* 构造者的困惑
* 使用了两个具有相同参数数量的 构造函数的参数名称相同
*/
public class ConstructorConfusion {
private String someValue;
public ConstructorConfusion(String someValue) {
System.out.println("ConstructorConfusion(String) called");
this.someValue = someValue;
}
public ConstructorConfusion(int someValue) {
System.out.println("ConstructorConfusion(int) called");
this.someValue = "Number:"+someValue;
}
@Override
public String toString() {
return someValue;
}
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:constructorConfusion-xml.xml");
ctx.refresh();
ConstructorConfusion cc = (ConstructorConfusion)ctx.getBean("constructorConfusion");
System.out.println(cc);
ctx.close();
}
}
constructorConfusion-xml.xml
<?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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="constructorConfusion" class="com.anocation.spring5.ch3.ConstructorConfusion">
<constructor-arg>
<value>100</value>
</constructor-arg>
</bean>
</beans>
此时会打印100
想要使用int构造,可以添加类型
<constructor-arg type="int">
<value>100</value>
</constructor-arg>
使用注解方式
@Service("constructorConfusion")
public class ConstructorConfusion {
private String someValue;
public ConstructorConfusion(String someValue) {
System.out.println("ConstructorConfusion(String) called");
this.someValue = someValue;
}
@Autowired
public ConstructorConfusion(@Value("1000") int someValue) {
System.out.println("ConstructorConfusion(int) called");
this.someValue = "Number:"+someValue;
}
@Override
public String toString() {
return someValue;
}
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:app-context-annotation.xml");
ctx.refresh();
ConstructorConfusion cc = (ConstructorConfusion)ctx.getBean("constructorConfusion");
System.out.println(cc);
ctx.close();
}
}
app-context-annotation.xml
<?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"
xmlns:c="http://www.springframework.org/schema/c"
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">
<context:component-scan base-package="com.anocation.spring5.ch3.valueAnno"/>
<bean id="constructorConfusion" class="com.anocation.spring5.ch3.valueAnno.ConstructorConfusion">
<constructor-arg type="int">
<value>123456</value>
</constructor-arg>
</bean>
</beans>
@Component
public class Inspiration {
private String lyric = "I can keep the door cracked open , to let light through";
public Inspiration(@Value("For all my running, I can understand")String lyric) {
this.lyric = lyric;
}
public String getLyric() {
return lyric;
}
public void setLyric(String lyric) {
this.lyric = lyric;
}
}
@Service("singer")
public class Singer {
@Autowired
private Inspiration inspiration;
public void sing(){
System.out.println("..."+inspiration.getLyric());
}
}
public class Fieldinjection {
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:app-context-annotation.xml");
ctx.refresh();
Singer singer = ctx.getBean(Singer.class);
singer.sing();
ctx.close();
}
}
<context:component-scan base-package="com.anocation.spring5.ch3.annotated"/>
注入简单值
public class InjectSimple {
private String name;
private int age;
private float height;
private boolean programmer;
private Long ageInSeconds;
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:app-config.xml");
ctx.refresh();
InjectSimple simple = ctx.getBean(InjectSimple.class);
System.out.println(simple);
ctx.close();
}
//省略
//setter
//getter
//toString
}
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="injectSimple" class="com.anocation.spring5.ch3.xml.InjectSimple"
p:name="fly"
p:age="11"
p:height="1.21"
p:programmer="false"
p:ageInSeconds="121212121211212"
/>
</beans>
注解方式
@Service("injectSimple")
public class InjectSimple {
@Value("fly")
private String name;
@Value("12")
private int age;
@Value("1.54")
private float height;
@Value("false")
private boolean programmer;
@Value("1213131231231")
private Long ageInSeconds;
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
// ctx.load("classpath:app-config.xml");
ctx.load("classpath:app-context-annotation.xml");
ctx.refresh();
InjectSimple simple = ctx.getBean(InjectSimple.class);
System.out.println(simple);
ctx.close();
}
//省略
//setter
//getter
//toString
}
<context:component-scan base-package="com.anocation.spring5.ch3.xml"/>
SpEL 能够动态评估表达式
public class InjectSimpleConfig {
private String name = "fly";
private int age = 12;
private float height = 1.43f;
private boolean programmer = false;
private Long ageInSeconds = 121212121L;
public String getName() {
return name;
}
public int getAge() {
return age;
}
public float getHeight() {
return height;
}
public boolean isProgrammer() {
return programmer;
}
public Long getAgeInSeconds() {
return ageInSeconds;
}
}
InjectSimpleConfig.xml
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="injectSimpleConfig" class="com.anocation.spring5.ch3.xml.InjectSimpleConfig"/>
<bean id="injectSimpleSpel" class="com.anocation.spring5.ch3.xml.InjectSimpleSpel"
p:name="#{injectSimpleConfig.name+1}"
p:age="#{injectSimpleConfig.age+1}"
p:height="#{injectSimpleConfig.height}"
p:programmer="#{injectSimpleConfig.programmer}"
p:ageInSeconds="#{injectSimpleConfig.ageInSeconds}"
/>
</beans>
/**
* 测试配置
* {@link InjectSimpleConfig}
*/
public class InjectSimpleSpel {
private String name;
private int age;
private float height;
private boolean programmer;
private Long ageInSeconds;
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:InjectSimpleConfig.xml");
ctx.refresh();
InjectSimpleSpel simple = ctx.getBean(InjectSimpleSpel.class);
System.out.println(simple);
ctx.close();
}
//省略
//getter
//setter
//toString
}
当使用注解式的值注入时,只需要用 SpEL 表达式替换值注解即可
@Component("injectSimpleConfig")
public class InjectSimpleConfig {
//省略
}
@Service("injectSimpleSpel")
public class InjectSimpleSpel {
@Value("#{injectSimpleConfig.name}")
private String name;
@Value("#{injectSimpleConfig.age}")
private int age;
@Value("#{injectSimpleConfig.height}")
private float height;
@Value("#{injectSimpleConfig.programmer}")
private boolean programmer;
@Value("#{injectSimpleConfig.ageInSeconds}")
private Long ageInSeconds;
//省略
}
<context:component-scan base-package="com.anocation.spring5.ch3.xml"/>
public class BookwormOracle implements Oracle {
@Override
public String defineMeaningOfLife() {
return "go see the world instead";
}
}
public class InjectRef {
private Oracle oracle;
public void setOracle(Oracle oracle) {
this.oracle = oracle;
}
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:injectRef-xml.xml");
ctx.refresh();
InjectRef injectRef = ctx.getBean(InjectRef.class);
System.out.println(injectRef);
ctx.close();
}
@Override
public String toString() {
return oracle.defineMeaningOfLife();
}
}
<?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">
<bean id="oracle" name="wiseworm" class="com.anocation.spring5.ch3.BookwormOracle"/>
<bean id="injectRef" class="com.anocation.spring5.ch3.InjectRef">
<property name="oracle">
<!--<ref bean="oracle"/>-->
<ref bean="wiseworm"/>
</property>
</bean>
</beans>
Spring 支持ApplicationContext 的层次结构,因此一个上下文(以及相关的 BeanFactory)被认为是另一个上下文的 父级。通过ApplicationContexts 嵌套, 能够将配置分割成不同的文件, 这对于包含许多 bean 的大型项目来说简直就 是天赐之物
public class Song {
private String title;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
parent-context.xml
<bean id="childTitle" class="java.lang.String" c:_0="daughters"/>
<bean id="parentTitle" class="java.lang.String" c:_0="gravity"/>
child-context.xml
<bean id="song1" class="com.anocation.spring5.ch3.Song" p:title-ref="parentTitle"/>
<bean id="song2" class="com.anocation.spring5.ch3.Song" p:title-ref="childTitle"/>
<bean id="song3" class="com.anocation.spring5.ch3.Song">
<property name="title">
<ref parent="parentTitle"/>
</property>
</bean>
song! 和 song3 bean 都引用了父 ApplicationContext 中的 bean, 而 song2 bean 则引用了子 Application Context 中的 bean
可以选择<list>、<map>、
public class LyricHolder {
private String value = "You be the DJ, I'll be the driver";
@Override
public String toString() {
return value;
}
}
<bean id="lyricHolder" class="com.anocation.spring5.ch3.xml.LyricHolder"/>
<bean id="injection" class="com.anocation.spring5.ch3.xml.Collectioninjection">
<property name="map">
<map>
<!-- <entry key="someValue"><value>It's a Friday, we finally made it</value></entry>-->
<!-- <entry key="someBean"><ref bean="lyricHolder"/></entry>-->
<entry key="someValue" value="It's a Friday, we finally made it"/>
<entry key="someBean" value-ref="lyricHolder"/>
</map>
</property>
<property name="props">
<props>
<prop key="firstName">John</prop>
<prop key="secondName">Mayer</prop>
</props>
</property>
<property name="set">
<set>
<value>I can’t believe I get to see your face</value>
<ref bean="lyricHolder"/>
</set>
</property>
<property name="list">
<list>
<value>You’ve been working and I’ve been waiting</value>
<ref bean="lyricHolder"/>
</list>
</property>
</bean>
public class Collectioninjection {
private Map<String,Object> map;
private Properties props;
private Set set;
private List list;
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:app-context-xml.xml");
ctx.refresh();
Collectioninjection injection = (Collectioninjection)ctx.getBean("injection");
injection.displayInfo();
ctx.close();
}
public void displayInfo(){
System.out.println("Map contents:\n");
map.entrySet().stream().forEach(e-> System.out.println(e.getKey()+"---"+e.getValue()));
System.out.println("\nProperties contents:\n");
props.entrySet().stream().forEach(e-> System.out.println(e.getKey()+"---"+e.getValue()));
System.out.println("\nSet contents:\n");
set.forEach(System.out::println);
System.out.println("\nList contents:\n");
list.forEach(System.out::println);
}
public void setMap(Map<String, Object> map) {
this.map = map;
}
public void setProps(Properties props) {
this.props = props;
}
public void setSet(Set set) {
this.set = set;
}
public void setList(List list) {
this.list = list;
}
}
注解方式
@Service("lyricHolder")
public class LyricHolder {
private String value = "You be the DJ, I'll be the driver";
@Override
public String toString() {
return value;
}
}
<?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"
xmlns:util="http://www.springframework.org/schema/util"
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
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<context:component-scan base-package="com.anocation.spring5.ch3.annotation"/>
<util:map id="map" map-class="java.util.HashMap">
<entry key="someValue" value="It's a Friday, we finally made it"/>
<entry key="someBean" value-ref="lyricHolder"/>
</util:map>
<util:properties id="props">
<prop key="firstName">John</prop>
<prop key="secondName">Mayer</prop>
</util:properties>
<util:set id="set" set-class="java.util.HashSet">
<value>I can’t believe I get to see your face</value>
<ref bean="lyricHolder"/>
</util:set>
<util:list id="list" list-class="java.util.ArrayList">
<value>You’ve been working and I’ve been waiting</value>
<ref bean="lyricHolder"/>
</util:list>
</beans>
@Service("injection")
public class Collectioninjection {
@Resource(name = "map")
private Map<String,Object> map;
@Resource(name = "props")
private Properties props;
@Resource(name = "set")
private Set set;
@Resource(name = "list")
private List list;
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:app-context-annotation2.xml");
ctx.refresh();
Collectioninjection injection = (Collectioninjection)ctx.getBean("injection");
injection.displayInfo();
ctx.close();
}
public void displayInfo(){
System.out.println("Map contents:\n");
map.entrySet().stream().forEach(e-> System.out.println(e.getKey()+"---"+e.getValue()));
System.out.println("\nProperties contents:\n");
props.entrySet().stream().forEach(e-> System.out.println(e.getKey()+"---"+e.getValue()));
System.out.println("\nSet contents:\n");
set.forEach(System.out::println);
System.out.println("\nList contents:\n");
list.forEach(System.out::println);
}
public void setMap(Map<String, Object> map) {
this.map = map;
}
public void setProps(Properties props) {
this.props = props;
}
public void setSet(Set set) {
this.set = set;
}
public void setList(List list) {
this.list = list;
}
}
不仅限于注入原始值的集合,还可以注入bean 的集合或其他集合
@Autowired 注解始终将数组、集合和映射视为相应 bean 的集合,而目标 bean 类型从声明的集合值类型派生。例如,如采一个类 具有 List <ContentHolder>类型的属性并且定义了@Autowired i主解,那么 Spring会尝试将当前 ApplicationContext 中 所有 ContentHolder类型的 bean注入该属性(而不是配置文件中声明的<util:list>),这将导致意外的依赖项被注入;或 者如果没有 ContentHolder 类型的 bean, Spring 将抛出一个异常。 因此,对于集合类型注入,必须明确指示 Spring 通过指定@Resource 注解支持的 bean 名称来执行注入。
通过使用@Autowired 和@Qualifier,可以获得使用 bean 名称注入集合的等效配置
@Autowired
@Qualifier("map")
查找方法注入
方法替换
Spring 使用了 CGLIB 的动态字节码增强功能
public class Singer {
private String lyric = "You be the DJ, I'll be the driver";
public void sing() {
// System.out.println(lyric);
}
}
public interface DemoBean {
Singer getMySinger();
void doSomething();
}
public class StandardLookupDemoBean implements DemoBean {
private Singer mySinger;
public void setMySinger(Singer mySinger) {
this.mySinger = mySinger;
}
@Override
public Singer getMySinger() {
return this.mySinger;
}
@Override
public void doSomething() {
getMySinger().sing();
}
}
public abstract class AbstractLookupDemoBean implements DemoBean {
public abstract Singer getMySinger();
@Override
public void doSomething() {
getMySinger().sing();
}
}
<bean id="singer" class="com.anocation.spring5.ch3.xml.Singer" scope="prototype"/>
<bean id="abstractLookupBean" class="com.anocation.spring5.ch3.xml.AbstractLookupDemoBean">
<lookup-method name="getMySinger" bean="singer"/>
</bean>
<bean id="standardLookupBean" class="com.anocation.spring5.ch3.xml.StandardLookupDemoBean">
<property name="mySinger" ref="singer"/>
</bean>
public class LookUpDemo {
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:app-context-xml.xml");
ctx.refresh();
DemoBean abstractBean = ctx.getBean("abstractLookupBean", DemoBean.class);
DemoBean standardBean = ctx.getBean("standardLookupBean", DemoBean.class);
displayInfo("abstractBean",abstractBean);
displayInfo("standardBean",standardBean);
ctx.close();
}
public static void displayInfo(String beanName,DemoBean bean){
Singer singer1 = bean.getMySinger();
Singer singer2 = bean.getMySinger();
System.out.println(beanName+" ? "+(singer1==singer2));
StopWatch stopWatch = new StopWatch();
stopWatch.start("lookupDemo");
for (int x = 0; x < 100000; x++) {
Singer singer = bean.getMySinger();
singer.sing();
}
stopWatch.stop();
System.out.println(stopWatch.getTotalTimeMillis()+"ms");
//abstractBean ? false
//281ms
//standardBean ? true
//1ms
}
}
对于 abstractLookupBean bean, 每次调用 getMySinger都应该检索一个新的 Singer 实例,因此引用不应该相同。 而对于 standardLookupBean Bean,一个单一的 Singer 实例通过setter 注入被传递给 bean,并且该实例被存储且在每 次调用 getMySinger时返回,所以这两个引用应该是相同的。
使用注解
@Component("singer")
@Scope("prototype")
public class Singer {
private String lyric = "You be the DJ, I'll be the driver";
public void sing() {
// System.out.println(lyric);
}
}
@Component("standardLookupBean")
public class StandardLookupDemoBean implements DemoBean {
private Singer mySinger;
@Autowired
@Qualifier("singer")
public void setMySinger(Singer mySinger) {
this.mySinger = mySinger;
}
@Override
public Singer getMySinger() {
return this.mySinger;
}
@Override
public void doSomething() {
getMySinger().sing();
}
}
@Component("abstractLookupBean")
public abstract class AbstractLookupDemoBean implements DemoBean {
@Lookup("singer")
public abstract Singer getMySinger();
@Override
public void doSomething() {
getMySinger().sing();
}
}
当想要使用两个具有不同生命周期的 bean 时,可以使用查找方法注入。 当 bean 共享相同的生命周期时, 应该 避免使用查找方法注入,尤其是当这些 bean 都是单例时
有一个在 Spring 应用程序中使用的第三方库, 并且需要更改某个方法的逻辑。 此时,无法更改源代 码,因为它是由第三方提供的,所以一种解决方案是使用方法替换,使用自己的实现来替换该方法的逻辑。
public class ReplacementTarget {
public String formatMessage(String msg){
return "<h1>"+msg+"</h1>";
}
public String formatMessage(Object msg){
return "<h1>"+msg+"</h1>";
}
}
/**
* 如果想要替换一个方法,首先需要创建MethodReplacer接口的一个实现
*/
public class FormatMessageReplacer implements MethodReplacer {
@Override
public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
if (isFormatMessageMethod(method)){
String msg = (String) args[0];
return "<h2>"+msg+"</h2>";
}else {
throw new IllegalArgumentException("Unable to reimplement method"+method.getName());
}
}
private boolean isFormatMessageMethod(Method method){
if (method.getParameterTypes().length!=1){
return false;
}
if (!("formatMessage".equals(method.getName()))){
return false;
}
if (method.getReturnType()!=String.class){
return false;
}
if (method.getParameterTypes()[0]!=String.class){
return false;
}
return true;
}
}
<bean id="methodReplacer" class="com.anocation.spring5.ch3.xml.FormatMessageReplacer"/>
<bean id="replacementTarget" class="com.anocation.spring5.ch3.xml.ReplacementTarget">
<replaced-method name="formatMessage" replacer="methodReplacer">
<arg-type>String</arg-type>
</replaced-method>
</bean>
<bean id="standardTarget" class="com.anocation.spring5.ch3.xml.ReplacementTarget"/>
public class MethodReplacementDemo {
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:app-context-xml.xml");
ctx.refresh();
ReplacementTarget replacementTarget = ctx.getBean("replacementTarget", ReplacementTarget.class);
ReplacementTarget standardTarget = ctx.getBean("standardTarget", ReplacementTarget.class);
displayInfo(replacementTarget);
displayInfo(standardTarget);
ctx.close();
}
private static void displayInfo(ReplacementTarget target){
System.out.println(target.formatMessage("Thanks for playing , try again !"));
StopWatch stopWatch = new StopWatch();
stopWatch.start();
for (int i = 0; i < 1000000; i++) {
target.formatMessage("No filter in my head");
}
stopWatch.stop();
System.out.println(stopWatch.getTotalTimeMillis()+"ms");
//<h2>Thanks for playing , try again !</h2>
//206ms
//<h1>Thanks for playing , try again !</h1>
//27ms
//动态替换的方法比静态定义的芳法慢很多倍
}
}
在不同情况下,可以证明方法替换是非常有用的,尤其是当只想覆盖单个bean 的特定方法而不是相同类型的所 有 bean 时。 即使有这种说法,很多人也仍然倾向于使用标准的 Java 机制来重写方法,而不是依赖于运行时字节码 的增强。
应该避免针对多个不相关的方法使用单个 MethodReplacer, 这样会导致在代码查找应该重新实现的方法时执行不必要的字符串比较。 执行简单的检查以确保MethodReplacer使用正确的方法是很有用的,并且不会为代码增 加太多开销。
02.spring的依赖注入、配置ApplicationContext
原文:https://www.cnblogs.com/fly-book/p/12306930.html