Spring IOC&&AOP

Spring

Spring IOC (Inverse of Control)

思想:

IOC意思是控制反转,控制权由对象本身转向容器,由容器根据配置文件去创建实例并创建各个实例之间的依赖关系

这个容器叫做bean工厂;在Spring中,bean工厂创建的各个实例称作bean

原理:

利用java反射,就是在Spring运行时,bean工厂根据Spring的xml配置文件或扫描指定包下注解来动态地生成一个实例,并且调用对象里的方法的

Spring支持三种依赖注入方式,分别是属性(Setter方法)注入,接口注入和构造注入。

一般不采用接口注入,因为注入对象还必须实现某个接口,比较麻烦。

http://www.paymoon.com:8001/index.php/2017/01/06/why-spring-ioc-mechanism-is-not-new-but-reflection/

SpringMVC运行原理

  1. 客户端请求提交到DispatcherServlet
  2. 由DispatcherServlet控制器查询HandlerMapping,找到并分发到指定的Controller中。
  3. Controller调用业务逻辑处理后,返回ModelAndView
  4. DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图
  5. 视图负责将结果显示到客户端

http://www.cnblogs.com/xiaoxing/p/5836835.html

@Resource跟@Autowired比较

上面介绍中Controller中注入userService或者 Service层里面注入dao都是用@Resource标签,其实也可以使用@Autowired来替代,但是建议使用@Resource。下面说说这2者的区别:

  1. @Autowired和@Resource都可以用来装配bean,都可以写在字段上,或者方法上。

  2. @Autowired属于Spring的;@Resource为JSR-250标准的注释,属于J2EE的。

  3. @Autowired默认按类型装配,默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,例如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用

    例如:

    1
    2
    3
    @Autowired
    @Qualifier("baseDao")
    private BaseDao baseDao;
  4. @Resource,默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

    例如:

    1
    2
    @Resource(name="baseDao")
    private BaseDao baseDao;
    1. 之所以推荐使用@Resource,因为这个注解是属于J2EE的,减少了与spring的耦合。这样代码看起就比较优雅。

http://www.jianshu.com/p/135693f589c4

SpringAOP原理

AOP是通过动态代理来实现的,有两种常用的技术,一是JDK的动态代理,二是CGLIB,而无论是前者还是后者,都是生成动态生成类的字节码来实现的。JDK的动态代理只能处理接口实现的方法,而CGLIB则没有这个限制。因为字节码是动态生成的,所以可以在生成的字节码当中,在目标方法前后插入定义好的方法的调用。

切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象。 在Spring AOP中,切面可以使用通用类(基于模式的风格) 或者在普通类中以 @Aspect 注解(@AspectJ风格)来实现

连接点(Joinpoint): 在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。在Spring AOP中,一个连接点 总是 代表一个方法的执行。通过声明一个org.aspectj.lang.JoinPoint类型的参数可以使通知(Advice)的主体部分获得连接点信息。

通知(Advice):在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类型,其中包括“around”、“before”和“after”等通知。通知的类型将在后面部分进行讨论。许多AOP框架,包括Spring,都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。

切入点(Pointcut):匹配连接点(Joinpoint)的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。

引入(Introduction): (也被称为内部类型声明(inter-type declaration))。声明额外的方法或者某个类型的字段。 Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制。

织入(Weaving): 把切面(aspect)连接到其它的应用程序类型或者对象上,并创建一个被通知(advised)的对象。这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。 Spring和其他纯Java AOP框架一样,在运行时完成织入。

通知的类型:

前置通知(Before advice): 在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。

返回后通知(After returning advice): 在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。

抛出异常后通知(After throwing advice): 在方法抛出异常退出时执行的通知。

后通知(After (finally) advice): 当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

环绕通知(Around Advice): 包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型。环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。

原接口:很多种方法定义

委托类:实现接口的方法

代理类:引用委托类实现方法的同时,额外做一些事情

AOP速学路径

https://segmentfault.com/a/1190000007469982

jdk动态代理

使用java反射机制,在运行期时,插入自定义的方法调用

具体是通过Proxy和InvocationHandler这个接口来实现的,InvocationHandler里有invoke(Object proxy, Method method, Object[] args)这个方法,它可以有委托类方法和参数引用,所以可以在invoke方法中围绕着委托类的方法做一些前置、后置操作

Proxy会用newProxyInstance(ClassLoader,interfaces,InvocationHandlerImpl)生成动态代理类,这个代理类会实现委托类的接口,当执行代理类的方法时,实际上是执行InvocationHandler的invoke方法,所以就实现了之前我们的前置、后置操作

动态代理速学路径

https://segmentfault.com/a/1190000007089902

http://blog.csdn.net/qqHJQS/article/details/53402493

CGLIB代理

cglib是用asm框架生成的字节码文件,而且生成的动态代理类委托类的子类,所以委托类不能是final

利用MethodInterceptor接口的intercept方法,可以在这个方法里调用invokeSuper来操作委托类方法,同样就可以围绕着委托类的方法做一些前置、后置操作

速学路径:

http://www.deanwangpro.com/2017/02/08/aop-in-java/

http://blog.csdn.net/panyongcsd/article/details/53204719

http://www.importnew.com/20732.html

http://www.jianshu.com/p/d35e46f27187

Spring AOP应用场景

性能检测,访问控制,日志管理,事务

Spring Bean的作用域区别

Spring容器中的bean可以分为5个范围。所有范围的名称都是自说明的,但是为了避免混淆,还是让我们来解释一下:

  1. singleton:这种bean范围是默认的,这种范围确保不管接受到多少个请求,每个容器中只有一个bean的实例,单例的模式由bean factory自身来维护。
  2. prototype:原形范围与单例范围相反,为每一个bean请求提供一个实例。
  3. request:在请求bean范围内会每一个来自客户端的网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
  4. Session:与请求范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。
  5. global-session:global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。

全局作用域与Servlet中的session作用域效果相同。

Spring中的单例Beans是线程安全的吗

不是,Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。但实际上,大部分的Spring bean并没有可变的状态(比如Service类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。Spring原理上使用ThreadLocal来保证单例安全的。

最浅显的解决办法就是将单态bean的作用域由“singleton”变更为“prototype”。
当然,scope的值不止这两种,还包括了request,session 等。但用的最多的还是singleton单态,prototype多态。
singleton表示该bean全局只有一个实例,Spring中bean的scope默认也是singleton.
prototype表示该bean在每次被注入的时候,都要重新创建一个实例,这种情况适用于有状态的Bean.