Spring Framework(2):深入理解IoC和AOP

Deployment期间验证

实现一:

1     <bean id="theTargetBean" class="..."/>
2
3     <bean id="theClientBean" class="...">
4         <property name="targetName">
5             <idref bean="theTargetBean" />
6         </property>
7     </bean>

实现二:

1     <bean id="theTargetBean" class="..." />
2
3     <bean id="client" class="...">
4         <property name="targetName" value="theTargetBean" />
5     </bean>

方式1跟方式2得到的依赖关系完全一致,不同的是方式1在deployment的时候就会去判断名字为theTargetBean的bean是否有定义,方式2要推迟到client被实例化的时候才去判断名字为theTargetBean的bean是否有定义。

XML简写
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
命名空间p表示可以将<property>变成属性p:[name|name-ref]=”id”的方式出现于<bean>定义中;
命名空间c表示可以将<constructor-arg>变成属性c:[name|name-ref]=”id”的方式出现<bean>定义中;

提前初始化
<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.foo.AnotherBean"/>
缺省情况下ApplicationContext在Initialization Process的时候就会创建并配置所有Singleton Bean (没有依赖项的bean),如果lazy-init显示设置为true则表示取消提前初始化的功能,从而加快初始化速度并减少内存占用;对于<beans/>使用default-lazy-init=”true”属性进行批量设置。

方法注入(Lookup Method Injection)

Java代码

1 public abstract class CommandManager {
2     protected abstract Command createCommand();
3 }

Xml代码

1 <bean id="command" class="fiona.apple.AsyncCommand" scope="prototype">
2     <!-- inject dependencies here as required -->
3 </bean>
4
5 <bean id="commandManager" class="fiona.apple.CommandManager">
6     <lookup-method name="createCommand" bean="command"/>
7 </bean>

CommandManager中的createCommand方法根据不同要求需要不同的实现,通过配置文件的<lookup-method>可以指定不同bean定义的方法实现;如果一个bean是stateful的则需要将scope设置为prototype,在每次调用的时候都生成一个新的instance。
<lookup-method/>标签用于解决当一个singleton的Bean A需要引用另外一个非singleton的Bean B(也就是每一次引用Bean B都需要引用最新创建的实例);实现方式是动态创建一个CommandManager的子类,并复写指定的方法;
AOP综合使用JDK Dynamic Proxy和CGLIB对目标类进行代理,两者区别如下:
#1 JDK Dynamic Proxy方式使用Java Reflection技术,因此要求目标类有一个Interface,并且目标方法需要此Interface中申明,动态创建一个实现了Interface的类并在改类中调用目标类的方法;

 1 public class PerformanceMonitorProxy implements InvocationHandler {
 2
 3     private Object target;
 4
 5     public ServiceWithPerformanceMonitorProxy(Object target) {
 6         this.target = target;
 7     }
 8
 9     public static Object newProxyInstance(Object target) {
10         Class clazz = target.getClass();
11         return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(),
12                 new ServiceWithPerformanceMonitorProxy(target));
13     }
14
15     @Override
16     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
17         //do something before target function invocation
18         PerformanceMonitor.begin(method.getName());
19         Object result = method.invoke(target, args);
20         //do something after target function invocation
21         PerformanceMonitor.end(method.getName());
22         return result;
23     }
24 }

#2 CGLIB使用字节码技术,动态生成一个目标类的子类,通过over-write去覆盖目标方法;

 1 public class CGlibProxy implements MethodInterceptor {
 2     private Enhancer enhancer = new Enhancer();
 3     public Object getProxy(Class clazz) {
 4         enhancer.setSuperclass(clazz);
 5         enhancer.setCallback(this); // 代理执行时会回调此this持有的intercept方法,以实现代码织入
 6         return enhancer.create();
 7     }
 8
 9     @Override
10     public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
11         PerformanceMonitor.begin(method.getName());
12         Object result = methodProxy.invokeSuper(target, args);
13         // 下面这样是无法执行原有方法的,因为这里的target并不是原有类的实例,而是代理类的实例
14         // target :
15         // [email protected]d5a9d
16         // Object result = method.invoke(target, args);
17         PerformanceMonitor.end(method.getName());
18         return result;
19     }
20 }

Spring一般首选JDK Dynamic Proxy进行代理,如果遇到没有实现Interface的情况则使用CGLIB,当然可以通过下属设置强制使用CGLIB;

1 <aop:config proxy-target-class="true">
2     <!-- other beans defined here... -->
3 </aop:config>

Bean作用范围 (<bean ………. Scope=”…….” />)

Singleton:缺省值,一个Spring IoC容器中至多仅生成一个instance,被依赖者共享,stateless
Prototype:每次调用都会生成一个新的instance,不同依赖者使用不同的实例,stateful
Request:WebApplicationContext中一次HTTP请求中至多仅生成一个instance
Session:WebApplicationContext中一个HTTP Session中至多仅生成一个instance
Global Session:WebApplicationContext中一个Global HTTP Session中至多仅生成一个instance
Application:WebApplicationContext中一个ServletContext中至多仅生成一个instance

1     <bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
2         <aop:scoped-proxy/>
3     </bean>
4
5     <!-- a singleton-scoped bean injected with a proxy to the above bean -->
6     <bean id="userService" class="com.foo.SimpleUserService">
7         <property name="userPreferences" ref="userPreferences"/>
8     </bean>

<aop:scoped-proxy/>用于解决将一个shorter-lived scoped bean注入到一个longer-lived scoped bean时shorter-lived scoped bean提前失效的场景;由于singleton类仅有一次注入bean的机会,因此解决思路是在一开始就在longer-lived scoped bean(singleton)中注入一个proxy class作为代理类,如果shorter-lived scoped bean(session)已经失效,代理类会使用当前session scope的shorter-lived bean。

定制Bean的初始化和销毁动作

方法一:使用标注@PostConstruct和@PreDestroy;在bean的java类文件中添加。
这两个标注由CommonAnnotationBeanPostProcessor进行处理。

1 @PostConstruct
2 public void  init(){
3     System.out.println("init  method”);
4 }
5 @PreDestroy
6 public void  dostory(){
7     System.out.println("destory method");
8 }

方法二:使用xml配置属性init-method和destroy-method,或者在<beans/>中添加批量设置的属性default-init-method或者default-destroy-method;

1 <bean id="initAndDestroySeqBean"
2     class="com.chj.spring.InitAndDestroySeqBean"
3     init-method="initMethod"
4     destroy-method="destroyMethod"/>

方法三:使用接口InitializingBean和DisposableBean (不推荐)

 1 public class PersonService  implements InitializingBean,DisposableBean{
 2     @Override
 3     public void destroy() throws Exception {
 4         // TODO Auto-generated method stub
 5         System.out.println("init  method");
 6     }
 7     @Override
 8     public void afterPropertiesSet() throws Exception {
 9         // TODO Auto-generated method stub
10         System.out.println("init  method");
11     }
12 } 

执行顺序为@PostConstruct -> InitializingBean -> init-method

如果POJO需要获取容器的某些消息,可以实现下述接口;但是一旦实现这些接口之后就与Spring框架强耦合;

1 public interface ApplicationContextAware {
2     void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
3 }
4 public interface BeanNameAware {
5     void setBeanName(string name) throws BeansException;
6 }

Bean继承

当需要创建同一个class或者同一个parent class的多个不同状态的instance时,使用parent属性可以有效减少配置文件中需要填写的属性值;

 1 <bean id="inheritedTestBean" abstract="true"
 2         class="org.springframework.beans.TestBean">
 3     <property name="name" value="parent"/>
 4     <property name="age" value="1"/>
 5 </bean>
 6
 7 <bean id="inheritsWithDifferentClass"
 8         class="org.springframework.beans.DerivedTestBean"
 9         parent="inheritedTestBean" init-method="initialize">
10     <property name="name" value="override"/>
11     <!-- the age property value of 1 will be inherited from parent -->
12 </bean>

#1 inheritsTestBean中的abstract=true表示当前bean不能实例化;如果一个singleton bean不打算进行实例化,则需要加上abstract=true属性。
#2 inheritsWithDifferentClass中的class属性不需要extends自parent class,但必须与parent class bean定义的属性匹配;并且可省略,表示使用parent指定bean的class属性;

Spring容器扩展点接口
BeanPostProcessor可以进行customized的实例化、初始化、依赖装配、依赖验证等流程(处理annotation标签,比如@Autowired,@Resource等)。
BeanFactoryPostProcessor可以修改xml文件的bean metadata;Ordered接口控制先后执行顺序。

自动装配(Autowiring)
XML Injection在Annotation Injection之后执行,所以前者会覆盖后者的相同设置,比如如果<property/>或者<constructor-arg/>也针对同一属性进行装配,则@Autowire装配的内容被覆盖;自动装配不能指定简单类型,如String;并且容易造成匹配歧义从而抛出异常;

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xmlns:context="http://www.springframework.org/schema/context"
 5     xsi:schemaLocation="http://www.springframework.org/schema/beans
 6         http://www.springframework.org/schema/beans/spring-beans.xsd
 7         http://www.springframework.org/schema/context
 8         http://www.springframework.org/schema/context/spring-context.xsd">
 9
10     <context:annotation-config/>
11
12 </beans>

‘<context:annotation-config>’表示使用annotation对属性进行自动装配,同时还注册了一系列post processors(比如AutowiredAnnotationBeanPostProcessor);加入上述tag之后就可以在java class中使用如下annotation了。

@Required:应用于属性的setter方法,表示相关的property必须设置值,否则抛出异常,但不检查是否为空。
@Autowired:应用于属性或者属性的setter方法, 表示相关的property必须有且仅有一个匹配项;如果应用于Spring自定义的Interface(如ApplicationContext)则容器会自动赋值匹配,无需额外进行设置;@Autowired是基于类型匹配的,所以如果一个bean是collection或者map则不能用@Autowired而需要使用@Resource。

原文地址:https://www.cnblogs.com/leo-chen-2014/p/8111771.html

时间: 2024-10-21 01:36:51

Spring Framework(2):深入理解IoC和AOP的相关文章

Spring Framework的核心:IOC容器的实现

2.1   Spring IoC容器概述 2.1.1 IoC容器和依赖反转模式 依赖反转的要义,如果合作对象的引用或依赖关系的管理由具体对象来完成,会导致代码的高度耦合和可测性的降低.依赖控制反转的实现有很多种方式,在Spring中,IoC是实现这个模式的载体,它可以在对象生成或初始化时直接将数据注入到对象中,也可以将对象引用注入到对象数据域中的方式来注入对方法调用的依赖. IoC亦称为“依赖倒置原则”:高层次的模块,不应该依赖与低层次模块,他们都依赖于抽象.抽象不应该依赖于具体的实现,具体实现

深入理解Spring的两大特征(IOC和AOP)&lt;转&gt;

在某博主的博客上看到一篇解释Spring的两大核心IOC与AOP的文章,借此转发一下,希望能够帮助到更多的人. 原文地址:https://blog.csdn.net/gloomy_114/article/details/68946881 众所周知,Spring的核心特性就是IOC和AOP,IOC(Inversion of Control),即"控制反转":AOP(Aspect-OrientedProgramming),即"面向切面编程". IOC:IOC,另外一种说

IOC和AOP的简单实现

一直使用spring,说起来就是IOC和AOP,看过不少原理的书,但是spring的代码太多,梳理起来很困难,于是想自己实现一下,昨天下午写出代码来,分享一下. 目标: 1.使用annotation编程进行分层,有service层和dao层(mapper层). 2.设置容器,将所有的实例注入到容器里,类似spring的applicationContext. 3.dao层使用接口,没有实现类,类似于ibitas的使用方式. 4.读取本地文件内容. 根据目标大概思考并实践了以下几点: 1.动态代理选

对Spring中的IOC与AOP简单理解(简单的理解,通俗易懂)

IOC与AOP是Spring中的核心:IOC是控制反转,AOP是面向对象编程,IOC采用了工厂设计模式,AOP采用了代理设计模式. 一.IOC IOC是控制反转,而控制反转是一种思想,而DI是依赖注入,是IOC的实现,DI有构造注入.属性注入(设值注入)(基于注解的方式或者基于XML的方式).在项目程序中,频繁的去手动创建对象,new对象使得代码间耦合度太大,而Spring提供了容器,通俗的讲:你无需知道对象的创建过程,只需从其中拿到结果就可以了:把对象的创建以及各个对象间的关系还有对象的销毁交

理解Spring中的IOC和AOP

我们是在使用Spring框架的过程中,其实就是为了使用IOC,依赖注入和AOP,面向切面编程,这两个是Spring的灵魂. 主要用到的设计模式有工厂模式和代理模式 IOC就是典型的工厂模式,通过sessionfactory去注入实例. AOP就是典型的代理模式的体现. 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关

对于Spring IOC 和 AOP 简单理解

IOC IOC(Inversion Of Controll,控制反转)是一种设计思想,将原本在程序中手动创建对象的控制权,交由给Spring框架来管理.IOC容器是Spring用来实现IOC的载体,IOC容器实际上就是一个Map(key, value),Map中存放的是各种对象. 这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来.IOC容器就像是一个工厂,当需要创建一个对象,只需要配置好配置文件/注解即可,不用考虑对象是如何被创建出来的,大大增加了项目的可维护性且降低了开发难度

Hello Spring Framework——面向切面编程(AOP)

本文主要参考了Spring官方文档第10章以及第11章和第40章的部分内容.如果要我总结Spring AOP的作用,不妨借鉴文档里的一段话:One of the key components of Spring is the AOP framework. While the Spring IoC container does not depend on AOP, meaning you do not need to use AOP if you don’t want to, AOP comple

Spring IOC及AOP学习总结

一.Spring IOC体系学习总结: Spring中有两个容器体系,一类是BeanFactory.另一类是ApplicationContext.BeanFactory提供了基础的容器功能.ApplicationContext则是基于BeanFactory建立的一套更加丰富的容器体系,基于ApplicationContext构建了Spring AOP体系(基于AOP体系又构建了声明式事务模型),I18n的支持,基于观察者模式的事件模型,多渠道的Bean资源的载入(比如从文件系统,从interne

Spring入门导读——IoC和AOP

和MyBatis系列不同的是,在正式开始Spring入门时,我们先来了解两个关于Spring核心的概念,IoC(Inverse of Control)控制反转和AOP()面向切面编程. 1.IoC(Inversion of Control)控制反转 什么是控制反转呢?可以这么通俗的来解释,我们通常写代码当一个类会关联另一个类是会直接在这个类里new,例如: 1 package day_30_spring; 2 3 /** 4 * @author 余林丰 5 * 6 * 2016年10月30日 7