spring工作原理

         对spring原理曾经写过类似的博客,地址:点击打开链接

         可是经过一些时间后,虽然天天用着spring,但一提到原理方面,就遗忘了呢?就记得AOP和IOC,但是没有清楚的讲出来呢?

思考了一下这个问题,总结如下。

         1、对于美食的喜爱,以后学习技术的过程中,多和美食相关联,和忘不掉的那些相关联。

         2、总是想着抓住最后一根稻草,却从来没有想过如何学会游泳。


IOC(inversion of control)控制反转

         概念:控制权有对象本身转向容器;由容器根据配置文件区创建实例并创建各个实例之间的依赖关系。

         核心:spring封装了抽象工厂模式;bean工厂创建的各个实例称作为bean。

         理解:喜欢吃的东西不一定自己亲自去做,交给食品加工厂去做不是更好吗。spring让一个对象不用创建new了,可以自动生产,这就是利用java的反射机制动态创建、调用对象,spring就是在运行时,根xml 是pring配置文件动态创建对象,和调用对象里的方法的。

         spring IOC 应用了单例模式,一次new一个全局对象,也可以在配置文件中进行配置,配置为不使用单例模式。


AOP(aspect oriented programming)面向切面编程

         1、不使用代理方式

         我们以这个为实例(http://blog.csdn.net/lovesummerforever/article/details/22668947),分别画出类图如下所示:


         2、代理的两种方式

         静态代理

         针对每个具体类分别编写代理类。针对一个接口编写一个代理类;


         动态代理

         针对一个方面编程写一个invocationHandler,然后借用JDK反射包中的proxy类为各个接口动态生成相应的代理类。

        

        http://blog.csdn.net/lovesummerforever/article/details/22664647本篇文章有很好的解释,比如针对调用接口的一些安全性检查,很多的类的方法都要改动,如果使用静态代理的话,建立代理类并继承真实的类,我们把安全性检查抽象出一个方法,这样每次调用接口方法前,都进行安全性检查,但是这种方法在代码编译的时候就创建代理类了,并且对原始类的修改,就要更改代理类,这样不符合类的开闭原则(软件设计应该对扩展开放,对修改关闭),那怎样动态的创建这个代理类(运行时),于是我们可以使用JDK自带的动态代理,在使用这个类的时候创建。

        如何使用JDK动态代理呢?

        1、实现InvocationHandler接口。

        2、通过Proxy,根据目标来生成代理。

        

        3、invoke方法,该方法中调用具体的切入方法。

        动态代理与静态代理区别

        静态代理:由程序员创建,再对其编译。在程序运行之前.class文件已经存在了。静态代理:在程序运行时,运用反射的机制动态创建而完成。无需程序员手动编写代码,利用jdk的动态代理机制即可,不仅简化了编程工作,且提高了软件的可扩展性,因为java的反射机制可以生成任意类型的动态代理。

        动态代理使用场景:不允许直接访问某些类,对访问要做特殊处理;或者对原始方法进行统一的扩展,例如日志的记录。



         springAOP

         springAOP核心也是动态代理,spring采用三种方式实现代理功能。1、java的动态代理方式。2、CGlib方式。3、Aspectj方式。

         默认模式

         spring使用java动态代理和CGlib的混合方式提供服务,即若对象实现了接口则spring自动采用java动态代理进行支持,否则则采用CGlib方式进行支持;也可以强制制定使用cglib方式代理,在配置文件中进行配置。(http://my.oschina.net/coldlemon/blog/178586)

         例如spring aop控制事务代码如下

	<!--事务相关控制-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">     
          <property name="dataSource" ref="dataSource"></property>
    </bean>     
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
    	<tx:attributes>
    		<tx:method name="add*" propagation="REQUIRED" read-only="false" rollback-for="Exception" />
      		<tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="Exception" />  		
		    <tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="Exception" />
		    <tx:method name="find*" read-only="true"/>
    	</tx:attributes>
    </tx:advice>
    <!--把事务控制在Service层-->
    <aop:config>    
	    <aop:pointcut id="pc" expression="execution(public * com.msc.biz.service.*.*(..))" /> 
	    <aop:advisor pointcut-ref="pc" advice-ref="txAdvice" />
    </aop:config>

         通过spring AOP特性来添加日志模块


         日志类:

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
  
  
/** 
 * 日志记录,添加、删除、修改方法AOP 
 * @author HotStrong 
 *  
 */  
public class LogAspect {  
	private static final Logger logger = Logger.getLogger(LogAspect.class);
          
	//在类里面写方法,方法名诗可以任意的。此处我用标准的before和after来表示  
    //此处的JoinPoint类可以获取,action所有的相关配置信息和request等内置对象。  
	 public void before(JoinPoint joinpoint){  
	 }  
	 public void after(JoinPoint joinpoint){  
	 } 
	  
//有参并有返回值的方法
	 public void logArgAndReturn(JoinPoint point, Object returnObj) {
		 //此方法返回的是一个数组,数组中包括request以及ActionCofig等类对象
		 logger.debug("执行的方法名为:"+point.getSignature());
		 Object[] args = point.getArgs();
		 String arg="";
	  if (args != null) {
	      for (Object obj : args) {
	    	  if(obj != null){
	    		  arg+=obj.toString()+",";
	    	  }
	    	 
	  }
	  logger.debug("执行的方法参数为:"+arg);
	  logger.debug("执行的方法返回值为:"+returnObj);  
     }
  }
}

         配置切面,切入点,和通知

 <!--针对于service中方法的监控--> 
	<bean id="logProcess" class="com.xsc.biz.common.LogAspect"></bean> <!--将日志类注入到bean中。-->
	<aop:config>  
               <aop:aspect id="b" ref="logProcess"><!--调用日志类-->  
               <aop:pointcut id="log" expression="execution(* com.xsc.biz.service.*.*(..))"/><!--配置在log包下所有的类在调用之前都会被拦截-->  
               <!--在log包下面所有的类的所有方法被调用之前都调用MyLog中的before方法-->
               <aop:before pointcut-ref="log" method="before"/> 
               <!--在log包下面所有的类的所有方法被调用之后都调用MyLog中的after方法--> 
               <aop:after pointcut-ref="log" method="after"/>  
  		<aop:after-returning method="logArgAndReturn" returning="returnObj" pointcut-ref="log"/>
               </aop:aspect>   
    </aop:config>


         这里配置<aop:aspect>是针对什么问题,调用哪个类。<aop:pointcut>是日志类方法的切入点,是在业务层,所有方法执行完毕切入。<aop:before><aop:after>是通知什么时候执行什么方法<aop:after-returning>是处理结果返回时的操作,执行方法logArgAndReturn。



         有些仓促,有时间一定会清晰的再整理一遍。





  • 39
    点赞
  • 101
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值