spring annotation
博客专区 > zswitos 的博客 > 博客详情
spring annotation
zswitos 发表于3年前
spring annotation
  • 发表于 3年前
  • 阅读 255
  • 收藏 8
  • 点赞 0
  • 评论 0

腾讯云 技术升级10大核心产品年终让利>>>   

摘要: spring 源码学习分享

Spring1

1、spring的IOC container(1)

    org.springframework.beans  org.springframework.context构成了springIoc的容器核心框架

1.1FactoryBean 这个接口是spring的创建类的所需要实现的接口

创建一个类

T getObject() throws Exception;

返回创建类的class

Class<?> getObjectType();

判断创建类是否为单例

boolean isSingleton();

1.2 BeanFactory 这个接口是spring对外提供可以配置的管理机制,管理任何类型的对象

//工厂对象的前缀
String FACTORY_BEAN_PREFIX = "&";


//根据名字获取的对象instance
Object getBean(String name) throws BeansException;


//根据名字和类型获取对象instance
<T> T getBean(String name, Class<T> requiredType) throws BeansException;

/根据类型获取一个类instance
<T> T getBean(Class<T> requiredType) throws BeansException;

//根据名字和构造器的参数(或者工厂方法的参数)返回一个类instance

Object getBean(String name, Object... args) throws BeansException;


//根据类型和和构造器的参数(或者工厂方法的参数)返回一个类instance
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;



//根据名字(bean definition name)判断是否含有一个类instance
boolean containsBean(String name);


判断是否为单例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

//判断是为原型

boolean isPrototype(String name) throws NoSuchBeanDefinitionException;


//根据类的定义名称判断是否是一个指定的类型
boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;

//根据定义名称返回一个类的Class对象

Class<?> getType(String name) throws NoSuchBeanDefinitionException;

//根据一个定义名字返回这个类的所有别名组成的数组
String[] getAliases(String name);

    

如下图是它的一个核心子类ApplicationContext

The interface org.springframework.context.ApplicationContext represents the Spring IoC
container and is responsible for instantiating, configuring, and assembling the aforementioned beans.

它是代表了spring ioc容器 初始化 配置 装载 它管理的bean

一个spring管理类的元数据定义有XML文件和注解两种方法,其中注解有分为Annotation-based configuration(spring自带的注解)和Java-based configuration(jdk自带注解@Configuration, @Bean, @Import and @DependsOn annotations)

.

XML配置

可以支持导入,以便按照实际需求拆分定义bean,如下:

<beans>
    <import resource="services.xml"/>
    <import resource="resources/messageSource.xml"/>
    <import resource="/resources/themeSource.xml"/>
    <bean id="bean1" class="..."/>
    <bean id="bean2" class="..."/>
</beans>


ApplicationContext 可以返回想要的bean

The ApplicationContext enables you to read bean definitions and access them as follows:
// create and configure beans
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});
// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);
// use configured instance
List<String> userList = service.getUsernameList();

不提倡在系统中这样应用的获取bean,它高度耦合了Spring的代码

ApplicationContext context =new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});

 应使用依赖注入的办法实现松耦合

(实质上的xml 或者注解配置的信息是元数据,它并不是spring真正使用的类)

Within the container itself, these bean definitions are represented as BeanDefinition objects, which
contain (among other information) the following metadata:


XML配置:
The idref element
一、
<bean id="theTargetBean" class="..."/>
<bean id="theClientBean" class="...">
<property name="targetName">
<idref bean="theTargetBean" />
</property>
</bean>
二、
<bean id="theTargetBean" class="..." />
<bean id="client" class="...">
<property name="targetName" value="theTargetBean" />
</bean>

两种方法区别:
    idref在部署的时候spring ioc容器要对idref的类去验证,看是否存在
    property在部署的时候容器不会自动检测是否存在

spring的scope

Scope Description
singleton (Default) Scopes a single bean definition to a
single object instance per Spring IoC container.
prototype Scopes a single bean definition to any number of
object instances.
request Scopes a single bean definition to the lifecycle
of a single HTTP request; that is, each HTTP
request has its own instance of a bean created
off the back of a single bean definition. Only
Spring Framework
57Spring Framework Reference Documentation
Scope
Description
valid in the context of a web-aware Spring
ApplicationContext.
session Scopes a single bean definition to the lifecycle of
an HTTP Session. Only valid in the context of a
web-aware Spring ApplicationContext.
global session Scopes a single bean definition to the lifecycle
of a global HTTP Session. Typically only
valid when used in a portlet context. Only
valid in the context of a web-aware Spring
ApplicationContext.
application Scopes a single bean definition to the lifecycle of
a ServletContext. Only valid in the context of
a web-aware Spring ApplicationContext.

single如下图



prototype如下图:


但是在single的scope下引用prototype的时候只是会出现问题,bean的引用关系在第一次初始化的时候就会被确定,single的属性一直不会被更新,所以prototype的对象不会被更新为最新创建的对象,解决办法如下:

public abstract class Chinese implements Person  
{  
    public Chinese()  
    {  
        System.out.pritln("Spring实例化主调bean:Chinese实例...");  
    }  
    //定义一个抽象方法,该方法将由Spring负责实现  
    publc abstract getAxe();  
    public void useAxe()  
    {  
        System.out.println("正在使用"+getAxe()+"看菜!");  
    }  
      
}  


为了让Spring知道如何实现该方法,我们需要在配置文件中使用<lookup-method.../>元素指定如下两个属性:name:指定需要让Spring实现的方法
bean:指定Spring实现该方法后的返回值。


<bean id="chinese" class="com.feng.service.impl.Chinese">  
    <!--指定getAxe方法返回steelAxe  
    每次调用getAxe方法将获取新的steelAxe对象-->  
    <look-method name="getAxe" bean="steelAxe"/>  
    -->  
</bean>  

上面的代码指定Spring将负责实现getAxe()方法,该方法的返回值是容器中的steelAxe Bean实例。
(引用自博客:http://blog.csdn.net/howlaa/article/details/8332519,感谢博主)


Request Scope

If you access scoped beans within Spring Web MVC, in effect, within a request that is processed
by the Spring DispatcherServlet, or DispatcherPortlet, then no special setup is necessary:
DispatcherServlet and DispatcherPortlet already expose all relevant state.

使用DispatcherServlet代理的类都是request scope

注意:

If you use a Servlet 2.5 web container, with requests processed outside of
Spring’s DispatcherServlet (for example, when using JSF or Struts), you need
to register the org.springframework.web.context.request.RequestContextListener
ServletRequestListener.

使用Servlet 2.5 web需要使用该RequestContextListener进行转换!


LifeCycle


                                                                                (图片摘自:http://developer.51cto.com/art/201104/255961.htm 感谢博主! )



一、spring Bean的作用域:scope=singleton(默认,单例,生成一个实例)

二、spring Bean的作用域:scope=prototype(多线程, 生成多个实例)

三、单例模式,默认在程序初始化的时候实例化(lazy-init="false")

四、prototype,getBean的时候才是实例化

五、lazy-init 只对单例模式起作用,对 prototype 不起作用(因为  prototype 默认就不是程序初始化的时候实例化的

1.容器寻找Bean的定义信息并且将其实例化。

2.受用依赖注入,Spring按照Bean定义信息配置Bean的所有属性。

3.如果Bean实现了BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的ID。

4.如果Bean实现了BeanFactoryAware接口,工厂调用setBeanFactory()方法传入工厂自身。

5.如果BeanPostProcessor和Bean关联,那么它们的postProcessBeforeInitialzation()方法将被调用。

6.如果Bean指定了init-method方法,它将被调用。

7.最后,如果有BeanPsotProcessor和Bean关联,那么它们的postProcessAfterInitialization()方法将被调用。
到这个时候,Bean已经可以被应用系统使用了,并且将被保留在Bean Factory中知道它不再需要。

有两种方法可以把它从Bean Factory中删除掉。

1.如果Bean实现了DisposableBean接口,destory()方法被调用。

2.如果指定了订制的销毁方法,就调用这个方法。

Bean在Spring应用上下文的生命周期与在Bean工厂中的生命周期只有一点不同,
唯一不同的是,如果Bean实现了ApplicationContextAwre接口,setApplicationContext()方法被调用。

只有singleton行为的bean接受容器管理生命周期。
non-singleton行为的bean,Spring容器仅仅是new的替代,容器只负责创建。


对于singleton bean,Spring容器知道bean何时实例化结束,何时销毁,
Spring可以管理实例化结束之后,和销毁之前的行为,管理bean的生命周期行为主要未如下两个时机:
Bean全部依赖注入之后
Bean即将销毁之前

1)依赖关系注入后的行为实现:
有两种方法:A.编写init方法  B.实现InitializingBean接口
afterPropertiesSet和init同时出现,前者先于后者执行,使用init方法,需要对配置文件加入init-method属性

2)bean销毁之前的行为
有两种方法:A.编写close方法  B.实现DisposableBean接口
destroy和close同时出现,前者先于后者执行,使用close方法,需要对配置文件加入destroy-method属性

(摘自:http://blog.csdn.net/java958199586/article/details/7469147,感谢博主!)

清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责

生命周期就是springIOC容器在初始化一个bean的时候的预留一些接口,(每个时期都有有三个等级:Bean级别,BeanFactory级别:,Application级别)


自定义的Bean不到万不得已不要直接引用Spring API产生耦合,这是种下一个孽缘,会有恶果的,能用注解用注解,这才是善缘。

如果你想修改一个spring ioc 并未对外暴露的api,可以通过集成一个BeanPostProcessor来达到目的,同理可以修改BeanFactory

a BeanPostProcessor yourself. For more information, see Section 5.8, “Container Extension Points

/**
* Factory hook that allows for custom modification of new bean instances,
* e.g. checking for marker interfaces or wrapping them with proxies.
*
* <p>ApplicationContexts can autodetect BeanPostProcessor beans in their
* bean definitions and apply them to any beans subsequently created.
* Plain bean factories allow for programmatic registration of post-processors,
* applying to all beans created through this factory.
*
* <p>Typically, post-processors that populate beans via marker interfaces
* or the like will implement {@link #postProcessBeforeInitialization},
* while post-processors that wrap beans with proxies will normally
* implement {@link #postProcessAfterInitialization}.
*
* @author Juergen Hoeller
* @since 10.10.2003
* @see InstantiationAwareBeanPostProcessor
* @see DestructionAwareBeanPostProcessor
* @see ConfigurableBeanFactory#addBeanPostProcessor
* @see BeanFactoryPostProcessor
*/
public interface BeanPostProcessor {

  /**
   * Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean
   * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
   * or a custom init-method). The bean will already be populated with property values.
   * The returned bean instance may be a wrapper around the original.
   * @param bean the new bean instance
   * @param beanName the name of the bean
   * @return the bean instance to use, either the original or a wrapped one; if
   * {@code null}, no subsequent BeanPostProcessors will be invoked
   * @throws org.springframework.beans.BeansException in case of errors
   * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
   */
  Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

  /**
   * Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean
   * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
   * or a custom init-method). The bean will already be populated with property values.
   * The returned bean instance may be a wrapper around the original.
   * <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean
   * instance and the objects created by the FactoryBean (as of Spring 2.0). The
   * post-processor can decide whether to apply to either the FactoryBean or created
   * objects or both through corresponding {@code bean instanceof FactoryBean} checks.
   * <p>This callback will also be invoked after a short-circuiting triggered by a
   * {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
   * in contrast to all other BeanPostProcessor callbacks.
   * @param bean the new bean instance
   * @param beanName the name of the bean
   * @return the bean instance to use, either the original or a wrapped one; if
   * {@code null}, no subsequent BeanPostProcessors will be invoked
   * @throws org.springframework.beans.BeansException in case of errors
   * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
   * @see org.springframework.beans.factory.FactoryBean
   */
  Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

}
/**
* Allows for custom modification of an application context's bean definitions,
* adapting the bean property values of the context's underlying bean factory.
*
* <p>Application contexts can auto-detect BeanFactoryPostProcessor beans in
* their bean definitions and apply them before any other beans get created.
*
* <p>Useful for custom config files targeted at system administrators that
* override bean properties configured in the application context.
*
* <p>See PropertyResourceConfigurer and its concrete implementations
* for out-of-the-box solutions that address such configuration needs.
*
* <p>A BeanFactoryPostProcessor may interact with and modify bean
* definitions, but never bean instances. Doing so may cause premature bean
* instantiation, violating the container and causing unintended side-effects.
* If bean instance interaction is required, consider implementing
* {@link BeanPostProcessor} instead.
*
* @author Juergen Hoeller
* @since 06.07.2003
* @see BeanPostProcessor
* @see PropertyResourceConfigurer
*/
public interface BeanFactoryPostProcessor {

  /**
   * Modify the application context's internal bean factory after its standard
   * initialization. All bean definitions will have been loaded, but no beans
   * will have been instantiated yet. This allows for overriding or adding
   * properties even to eager-initializing beans.
   * @param beanFactory the bean factory used by the application context
   * @throws org.springframework.beans.BeansException in case of errors
   */
  void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

由衷赞叹的spring设计如此之灵活,可扩展性如此之高啊,顶礼膜拜!(可以借鉴到自己的代码之中)


初始化:
public interface
InitializingBean {

  /**
   * Invoked by a BeanFactory after it has set all bean properties supplied
   * (and satisfied BeanFactoryAware and ApplicationContextAware).
   * <p>This method allows the bean instance to perform initialization only
   * possible when all bean properties have been set and to throw an
   * exception in the event of misconfiguration.
   * @throws Exception in the event of misconfiguration (such
   * as failure to set an essential property) or if initialization fails.
   */
  void afterPropertiesSet() throws Exception;

}
(@PostConstruct) 初始化的接口(注解) init-method


销毁:
public interface DisposableBean {

  /**
   * Invoked by a BeanFactory on destruction of a singleton.
   * @throws Exception in case of shutdown errors.
   * Exceptions will get logged but not rethrown to allow
   * other beans to release their resources too.
   */
  void destroy() throws Exception;

}
(@PreDestroy)销毁的接口(注解) destroy-method





给一个bean注入一个ApplicationContext
public interface
ApplicationContextAware extends Aware {

  /**
   * Set the ApplicationContext that this object runs in.
   * Normally this call will be used to initialize the object.
   * <p>Invoked after population of normal bean properties but before an init callback such
   * as {@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}
   * or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},
   * {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and
   * {@link MessageSourceAware}, if applicable.
   * @param applicationContext the ApplicationContext object to be used by this object
   * @throws ApplicationContextException in case of context initialization errors
   * @throws BeansException if thrown by application context methods
   * @see org.springframework.beans.factory.BeanInitializationException
   */
  void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}
给一个Bean注入创建他的工厂
public interface
BeanFactoryAware extends Aware {

  /**
   * Callback that supplies the owning factory to a bean instance.
   * <p>Invoked after the population of normal bean properties
   * but before an initialization callback such as
   * {@link InitializingBean#afterPropertiesSet()} or a custom init-method.
   * @param beanFactory owning BeanFactory (never {@code null}).
   * The bean can immediately call methods on the factory.
   * @throws BeansException in case of initialization errors
   * @see BeanInitializationException
   */
  void setBeanFactory(BeanFactory beanFactory) throws BeansException;

}
给一个bean注入他自己的内存注册的ID
public interface
BeanNameAware extends Aware {

  /**
   * Set the name of the bean in the bean factory that created this bean.
   * <p>Invoked after population of normal bean properties but before an
   * init callback such as {@link InitializingBean#afterPropertiesSet()}
   * or a custom init-method.
   * @param name the name of the bean in the factory.
   * Note that this name is the actual bean name used in the factory, which may
   * differ from the originally specified name: in particular for inner bean
   * names, the actual bean name might have been made unique through appending
   * "#..." suffixes. Use the {@link BeanFactoryUtils#originalBeanName(String)}
   * method to extract the original bean name (without suffix), if desired.
   */
  void setBeanName(String name);

}

这样的做法还是不好滴,因为又产生了spring的依赖,spring 2.5以后可以支持@Autowired这个注解,所以,spring一直提倡在自己代码内不要直接依赖springAPI,不然注解,不然xml配置!

<bean id="inheritedTestBeanWithoutClass" abstract="true">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean>
<bean id="inheritsWithClass" class="org.springframework.beans.DerivedTestBean"
parent="inheritedTestBeanWithoutClass" init-method="initialize">
<property name="name" value="override"/>
<!-- age will inherit the value of 1 from the parent bean definition-->
</bean>

spring的继承配置,当父类配置为abstract="true" 仅仅能被当天的xml模板使用,不能被初始化长生实体类,也不能被当作ref去被别的类引用,会报错的被引用了

Customizing instantiation logic with a FactoryBean

如果你的类初始化需要大量工作流程,过于复杂,不用担心,Spring IOC为你准备了FactoryBean,只有实现此接口你便可以随心所欲创造你的类,不需要在xml配置那么多的元算,如此优雅配置即可:

<bean id="factoryBeanOne" class="com.study.demo.factorybean.SimpleFactoryBean" > </Bean>
标签: spring
共有 人打赏支持
粉丝 5
博文 51
码字总数 46347
×
zswitos
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: