博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《Spring揭秘》——IOC梳理1(基础,基于注解的配置)
阅读量:6227 次
发布时间:2019-06-21

本文共 8458 字,大约阅读时间需要 28 分钟。

依赖注入的三种方式:

1、构造方法注入:对象构造完成后,即进入就绪状态,可以马上使用。缺点是有时候构造方法的参数列表较长,构造方法无法被继承,无法设置默认值。

2、setter方法注入:相对宽松,可在对象构造完成后再注入。setter方法可以被继承,允许设置默认值。缺点是无法在构造完成后就进入就绪状态。

3、接口注入:类需要实现某个接口,接口定义了注入方法,方法的参数即为所依赖对象的类型。(不推荐,较为死板和烦琐。)

IoC Service Provider的职责:

业务对象的构建管理:业务对象无需关心所依赖的对象如何构建如何取得,交由IoC Service Provider进行构建;

业务对象的依赖绑定:IoC Service Provider的最终使命所在,通过结合之前构建和管理的所有业务对象,以及各个业务对象间可以识别的依赖关系,将这些对象所依赖的对象进行绑定。

Spring提供了两种容器类型:

BeanFactory:基础类型IOC容器,提供完整的IOC服务支持。默认采用延迟初始化策略,容器启动速度快,所要的资源有限。

ApplicationContext:ApplicationContext在BeanFactory的基础上构建,是相对高级的容器实现,拥有BeanFactory的所有支持,且提供了其他高级特性。其管理的对象会在该容器启动后,默认全部初始化并绑定完成。所以,该容器会需要更多系统资源。

BeanFactoryXML之旅:

<beans>:XML配置文件中最顶层的元素,它下面可以包含0个或1个<description>和多个<bean>以及<import>或者<alias>。属性设置包括:default-lazy-init 、default-autowire 、default-init-method 、default-destroy-method 、default-dependency-check 。

<description>:指定一些描述性信息。

<import>:如果A.xml中的<bean>定义可能依赖B.xml中的某些<bean>定义,那就在A.xml中使用<import>将B.xml引入到A.xml。

<alias>:当bean名称过长时,可以通过alias来指定别名。<alias name="aabbcc" alias="abc"/>

 

<bean>:id属性(内部bean可省)、class属性、(name属性)

<bean id="helloSpring" name="//test t" class="com.test.HelloSpring" ></bean> 

可以通过ApplicationContext的getBean("helloSpring")获取,还可以用"//test","t"代替,name可通过逗号、空格分割开。

 

构造方法注入:<constructor-arg>,若存在多个构造方法,可能要使用type和index属性。要注意index从0开始。

setter方法注入:要确保提供了无参构造方法。此外,<constructor-arg>和<property>可同时使用。

 

<list>:对应注入对象类型是java.util.List及其子类 或者 数组类型的依赖对象。有序。

<set>:对应注入对象类型是java.util.Set及其子类的依赖对象。无序。

<map>:对应注入对象类型是java.util.Map及其子类的依赖对象。

  
  

<props>:相当于简化后的<map>,key只为String类型。对应配置类型为java.util.Properties的对象依赖。

  
root
1234
  

若想配置的集合可以被复用,则可使用<util:list>、<util:set>、<util:map>。

  
str1
  
str2
  
str3

c命名空间(构造器)和p命名空间(属性赋值):相对而言更加简洁。不能直接使用集合类。

 

depend-on:使用depend-on来要求容器在初始化自身实例之前首先实例化其他的对象,要保证该对象一定先实例化。

autowire:5种自动绑定方式:no(默认),byName,byType,constructor,autodetect。推荐手动绑定,此外beans中也包含default-autowire,可进行统一配置。

dependency-check:对其所依赖的对象进行最终检查。不常使用。

lazy-init:延迟加载。注意的是若a对象设置了延迟加载,而其是另一个对象b的构造函数所需要的对象,b没有设置延迟加载,则a依然会被初始化。在beans属性中同样有default-lazy-init属性可进行统一配置。

 

bean的scope:singleton(默认,生命周期可直接参照IoC容器),prototype(当对象实例给请求方后,请求方负责对象后记生命周期的管理工作),request,session,global session。此外,自定义session参照P55。

关于继承:

  
    
  
  
    
  
  
    
  

newsProviderTemplate就相当于一个配置模板,这个bean不可以实例化,同时可以不指定class属性。当多个bean定义拥有多个相同属性配置的时候,会带来很大便利。此外,parent所指向的对象也可以不是abstract的,而是具体的。额外强调的一点:若不想容器在初始化的时候实例化某些对象,就可以将abstract属性设置为true,以避免容器实例化

工厂方法与 FactoryBean

1.静态工厂方法:

public class StaticBarInterfaceFactory {    public static BarInterface getInstance() {            return new BarInterfaceImpl();    }}

容器调用该静态方法工厂类的指定工厂方法(getInstance),并返回方法调用后的结果,即BarInterfaceImpl的实例。

有的工厂类的工厂方法可能需要参数来返回相应实例, 可以通过<constructor-arg>来指定工厂方法需要的参数 :

public class StaticBarInterfaceFactory{  public static BarInterface getInstance(Foobar foobar){    return new BarInterfaceImpl(foobar);  }}
  
    
  

针对静态工厂方法实现类的bean定义,使用<constructor-arg>传入的是工厂方法的参数,而不是静态工厂方法实现类的构造方法的参数。

2.非静态工厂方法:

public class NonStaticBarInterfaceFactory{   public BarInterface getInstance(){    return new BarInterfaceImpl();  } } 

使用factory-bean属性来指定工厂方法所在的工厂类实例,而不是通过class属性来指定工厂方法所在类的类型。指定工厂方法名则相同,都是通过factory-method属性进行的。

如果非静态工厂方法调用时也需要提供参数的话,处理方式是与静态的工厂方法相似的,都可以通过<constructor-arg>来指定方法调用参数。

3.FactoryBean

FactoryBeanSpring容器提供的一种可以扩展容器对象实例化逻辑的接口,FactoryBean本身就是生产对象的工厂。

使用FactoryBean的情况:当某些对象的实例化过程过于烦琐,通过XML配置过于复杂,使我们宁愿使用Java代码来完成这个实例化过程的时候,或者,某些第三方库不能直接注册到Spring容器的时候, 就可以实现org.springframework.beans.factory.FactoryBean接口,给出自己的对象实例化逻辑代码。

public class CarFactoryBean implements FactoryBean
{ private String brand; public void setBrand(String brand) { this.brand = brand; } @Override public Car getObject() throws Exception { // TODO Auto-generated method stub return new Car(brand, 500000); } @Override public Class
getObjectType() { // TODO Auto-generated method stub return Car.class; } @Override public boolean isSingleton() { // TODO Auto-generated method stub return true; }}

  <!-- 通过FactoryBean来配置实例  实际返回的实例通过getObject() -->

  <bean id="car" class="com.test.CarFactoryBean">
    <property name="brand" value="BMW"></property>
  </bean>

Spring容器内部许多地方了使用FactoryBean。比较常见的FactoryBean实现:JndiObjectFactoryBean;LocalSessionFactoryBean;SqlMapClientFactoryBean;ProxyFactoryBean;TransactionProxyFactoryBean。

方法注入与方法替换

上文代码中,newsBean为prototype,mockPersister为singleton,存在setNewsBean方法。当调用persistNews方法时会打印newsBean的信息(调用getNewsBean())。当我们按照该代码配置并多次调用persistNews时会发现:每次调用的newsBean是同一个,虽然newsBean的scope是prototype。

原因:但当容器将一个FXNewsBean的实例注入MockNewsPersister之后, MockNewsPersister就会一直持有这个FXNewsBean实例的引用。虽然每次输出都调用了getNewsBean()方法并返回了 FXNewsBean 的实例,但实际上每次返回的都是MockNewsPersister持有的容器第一次注入的实例。这就是问题之所在,在第一个实例注入后, MockNewsPersister再也没有重新向容器申请新的实例。

方法注入:

容器会为我们要进行方法注入的对象使用Cglib动态生成一个子类实现,从而替代当前对象。(依赖cglib)

  

通过<lookup-method>name属性指定需要注入的方法名, bean属性指定需要注入的对象。使用lookup方法注入是有一定范围的,一般是在通过一个Singleton Bean获取一个Prototype Bean时使用。

补充方法:使用BeanFactoryAware接口

Spring框架提供了一个BeanFactoryAware接口,容器在实例化实现了该接口的bean定义的过程中,会自动将容器本身注入该bean。这样,该bean就持有了它所处的BeanFactory的引用。(其实将应用与Spring框架类绑定在一起,实为下策。)

public interface BeanFactoryAware {  void setBeanFactory(BeanFactory beanFactory) throws BeansException; }
public class MockNewsPersister implements IFXNewsPersister,BeanFactoryAware {  private BeanFactory beanFactory;  public void setBeanFactory(BeanFactory bf) throws BeansException {    this.beanFactory = bf;  }  public void persistNews(FXNewsBean bean) {     persistNews();  }  public void persistNews(){
    System.out.println("persist bean:"+getNewsBean());  }  public FXNewsBean getNewsBean() {    return beanFactory.getBean("newsBean");   } }

补充方法2:使用ObjectFactoryCreatingFactoryBean (P62)

方法替换:

方法替换主要体现在方法的实现层面上,它可以灵活替换或者以新的方法实现覆盖掉原来某个方法的实现逻辑。基本上可以认为,方法替换可以帮助我们实现简单的方法拦截功能。 (但其实使用不多,一般多使用AOP。)

  ...  

注意providerReplacer 要implements MethodReplacer。(Spring3.x P108)

基于注解的配置

关于@Autowired:是按照类型匹配进行依赖注入的 ,类似于byType。如果没有一个和标注类型匹配的Bean,则会抛出异常。如果希望即使找不到匹配的Bean也不要抛出异常,可以使用required属性:@Autowired(required=false)。

//属性public class FXNewsProvider{  @Autowired  private IFXNewsListener newsListener;  @Autowired  private IFXNewsPersister newPersistener;}//构造方法定义:将根据构造方法参数类型,来决定将什么样的依赖对象注入给当前对象。@Autowiredpublic FXNewsProvider(IFXNewsListener newsListner,IFXNewsPersister newsPersister){  this.newsListener = newsListner;  this.newPersistener = newsPersister;}//方法定义:不仅可以标注于传统的setter方法之上,而且还可以标注于任意名称的方法定义之上,只要该方法定义了需要被注入的参数 @Autowiredpublic void setUp(IFXNewsListener newsListener,IFXNewsPersister newPersistener){  this.newsListener = newsListener;  this.newPersistener = newPersistener;} //对集合类进行标注:Spring会将容器中所有类型为Plugin的Bean注入到该变量中。 @Autowired(required=false) private List
plugins;

当@Autowired同时找到两个或者多个同一类型的对象实例,则需要配合@Qualifier,@Qualifier实际上是byName自动绑定的注解版。

@Autowired@Qualifier("reutersNewsListner")private IFXNewsListener newsListener; //除了在属性域中使用,还可以在方法中进行标注public void setUp(@Qualifier("reutersNewsListner") IFXNewsListener newsListener,IFXNewsPersister newPersistener){...}

关于<context:component-scan>

<context:component-scan>默认扫描的注解类型是@Component。为@Component标注的对象指定名称:@Component("userDao")。

@Component语义基础上细化后的@Repository、 @Service@Controller也同样可以在<context:component-scan>扫描到。使用案例如下:

spring.xml

springmvc.xml

include-filterexclude-filter可以使用的type类型有annotationassignableregex和aspectj四种。(具体参照Spring3.x P121)

此外,Bean默认作用范围是singleton,Spring提供了@Scope来进行显示的作用范围配置:

@Scope("prototype")@Componentpublic class Car{  ...}

对标准注解的支持:

Spring还支持JSR250@Resource@PostConstruct以及@PreDestroy。

@Resource@Autowired不同,它遵循的是byName自动绑定形式的行为准则:@Resource(name="djNewsListener")。

@PostConstruct :类似于init-method 。可以在一个Bean中定义多个@PostConstruct。

@PreDestroy :类似于destroy-method 。可以在一个Bean中定义多个@PreDestroy。 

转载于:https://www.cnblogs.com/weilanzz/p/6757406.html

你可能感兴趣的文章
聊聊连接池和线程
查看>>
Python——正則表達式(2)
查看>>
适合新人学习的iOS官方Demo
查看>>
拉开大变革序幕(下):分布式计算框架与大数据
查看>>
AndroidStudio 使用AIDL
查看>>
H.264 RTPpayload 格式------ H.264 视频 RTP 负载格式(包含AAC部分解析)
查看>>
poj 3468 A Simple Problem with Integers 【线段树-成段更新】
查看>>
HDU 4287-Intelligent IME(哈希)
查看>>
CentOS---网络配置详解
查看>>
CakePHP不支持path/to路径,前后台无法方法
查看>>
第1阶段——uboot分析之硬件初始化start.S(4)
查看>>
记dynamic的一个小坑 -- RuntimeBinderException:“object”未包括“xxx”的定义
查看>>
代写初中语文作文|代写初中语文作文技巧分享
查看>>
linux字符设备文件的打开操作
查看>>
Servlet介绍以及简单实例
查看>>
[js高手之路] 跟GhostWu一起封装一个字符串工具库-架构篇(1)
查看>>
Java.ftp上传下载
查看>>
【Node.js】4.从一个例子切入Node js的规范
查看>>
实施微服务架构的关键技术
查看>>
使用云服务器不得不知的操作禁忌
查看>>