proxy-target-class属性: proxy-target-class属性值决定是基于接口的仍是基于类的代理被建立。若是proxy-target-class 属性值被设置为true,那么基于类的代理将起做用(这时须要cglib库)。若是proxy-target-class属值被设置为false或者这个属性被省略,那么标准的JDK 基于接口的代理 Spring事务传播机制(面试题) 概述 当咱们调用一个基于Spring的Service接口方法(如UserService#addUser())时,它将运行于Spring管理的事务环境中,Service接口方法可能会在内部调用其它的Service接口方法以共同完成一个完整的业务操做,所以就会产生服务接口方法嵌套调用的状况,Spring经过事务传播行为控制当前的事务如何传播到被嵌套调用的目标服务接口方法中。 事务传播是Spring进行事务管理的重要概念,其重要性怎么强调都不为过。可是事务传播行为也是被误解最多的地方,在本文里,咱们将详细分析不一样事务传播行为的表现形式,掌握它们之间的区别。 事务传播行为种类 Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播: 事务传播行为类型 说明 PROPAGATION_REQUIRED(默认) 若是当前没有事务,就新建一个事务,若是已经存在一个事务中,加入到这个事务中。这是最多见的选择。 PROPAGATION_SUPPORTS 支持当前事务,若是当前没有事务,就以非事务方式执行。 PROPAGATION_MANDATORY 使用当前的事务,若是当前没有事务,就抛出异常。 PROPAGATION_REQUIRES_NEW 新建事务,若是当前存在事务,把当前事务挂起。 PROPAGATION_NOT_SUPPORTED 以非事务方式执行操做,若是当前存在事务,就把当前事务挂起。 PROPAGATION_NEVER 以非事务方式执行,若是当前存在事务,则抛出异常。 PROPAGATION_NESTED 若是当前存在事务,则在嵌套事务内执行(REQUIRES_NEW)。若是当前没有事务,则执行中PROPAGATION_REQUIRED相似的操做。 PROPAGATION_NOT_SUPPORTED @Override public boolean existsName(String name) { boolean result= this.flinkTypeDao.existsName(name)>0; //模拟作插入操做 FlinkType ft=new FlinkType(); ft.setTypeName("挂起事务"); this.flinkTypeDao.insert(ft); return result; } <tx:method name="insert*" propagation=" PROPAGATION_NOT_SUPPORTED " /> 以非事务的方式提交,若是存在事务,就将当前事务挂起,才会执行insert() Spring事务何时才能回滚? 发生 RuntimeException (子类)这种时机,才会发生回滚,不然不会回滚 小结 在Spring声明式事务管理的配置中,事务传播行为是最容易被误解的配置项,缘由在于事务传播行为名称(如PROPAGATION_NESTED:嵌套式事务)和代码结构的相似性上(业务类方法嵌套调用另外一个业务类方法)。这种误解在不少Spring开发者中普遍存在,本文深刻讲解了Spring事务传播行为对业务方法嵌套调用的真实影响,但愿能帮助读者化解对事务传播行为的困惑。 请写你常见的异常? IOException, SqlException, FileNotFoundException, ClassNotFoundException NullPointerException,NumberFormatException ,IndexOutOfBoundsException,ClassCastException, StackOverException,StackOverflowError(递归致使的死循环) MappingNotFoundException,DateTimeException , struts的通用配置: <!-- 约定大于配置/admin/Flinktype_list.action --> <package name="freemarkerPackage" namespace="/admin" extends="commonPackage" > <!-- /admin/Flinktype_list.action --> <action name="*_*" class="{1}Action" method="{2}"> <result name="{2}" type="freemarker">/admin/template/{1}/{2}.ftl</result> </action> </package> FlinktypeAction.java有个String list()-->return list() 交给freemarker编译-->模板文件/admin/Flinktype/list.action 默认状况事务传播: @Override public boolean existsName(String name) { boolean result= this.flinkTypeDao.existsName(name)>0; //模拟作插入操做 FlinkType ft=new FlinkType(); ft.setTypeName("挂起事务"); this.flinkTypeDao.insert(ft); return result; } <tx:advice id="myAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- 对你的哪些方法作哪些事务 --> <tx:method name="insert*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="execute*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> <!-- 以find,get,其它除上面的外方法,都是只读事务 --> <tx:method name="find*" propagation="REQUIRED" read-only="true" /> <tx:method name="get*" propagation="REQUIRED" read-only="true" /> <tx:method name="*" propagation="REQUIRED" read-only="true" /> </tx:attributes>此事务是一个只读事务,insert新增不能成功 要解决这个问题,有两种解决方案 1)、直接更改方法名, exsitsName-executeExistsName/insertExistsName/updateExistsName等 2)、更改事务传播行为existsName <tx:method name="existsName" propagation="PROPAGATION_REQUIRES_NEW" read-only="true" /> 1、Spring有2个最核心概念 Spring IoC(控制反转) 和 Spring AOP(面向切面) 2、spring由哪几个部分组成,每一个部份的使用 由7个部分组成 1)、Spring AOP 面向切面编程 (在程序运行的过程当中,动态地为程序添加额外的功能) 2)、Spring Core 核心 (管理全部的bean) 3)、Spring ORM 对第三方的ORM框的支持 4)、Spring DAO 对数据库和事务的支持和管理 5)、Spring Context 应用程序上下文 6)、Spring Web 支持web操做 7)、Spring Web MVC 本身开的MVC框架 核心容器: 核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。 Spring 上下文: Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。 Spring AOP: 经过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。因此,能够很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。经过使用 Spring AOP,不用依赖 EJB 组件,就能够将声明性事务管理集成到应用程序中。 Spring DAO: JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不一样数据库供应商抛出的错误消息。异常层次结构简化了错误处理,而且极大地下降了须要编写的异常代码数量(例如打开和关闭链接)。Spring DAO 的面向 JDBC 的异常听从通用的 DAO 异常层次结构。 Spring ORM: Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。全部这些都听从 Spring 的通用事务和 DAO 异常层次结构。 Spring Web 模块: Web 上下文模块创建在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。因此,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工做。 Spring MVC 框架: MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。经过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。 3、Spring IoC 管理全部的Bean,经过BeanFactory来管理的,它提供了建立类的2种方式: 3.1)、 单态Singleton 是默认的也是最经常使用的对象模型。 3.2)、原型 模型确保每次检索都会建立单独的对象。 4、Spring IoC 和 AOP的做用? IoC 你再也不手动的去new 对象,而是让Spring依赖注入对象(@Autowired ,@Resource) AOP 动态为程序添加额外的功能 (事务) 5、Spring优势 (了解) 低侵入式设计 独立于各类应用服务器 依赖注入特性将组件关系透明化,下降了耦合度 面向切面编程特性容许将通用任务进行集中式处理 与第三方框架的良好整合 6、Spring IoC 解耦 将组件对象的控制权从代码自己转移到外部容器 组件化的思想:分离关注点,接口和实现分离 依赖的注入:将组件的构建和使用分开 7、在web运行过程当中,除了扫包的方式 和@Resource @Autowired注入还有没有其它方式? WebApplicationContext webApplicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext( ServletActionContext.getServletContext()); Object obj=webApplicationContext .getBean("messagePojo"); 控制台中使用 ClassPathXmlApplicationContext cpa=new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); //获得spring管理的全部的对象 Object obj=cpa.getBean("messagePojo"); 8、Spring管理bean能够有3种形式来注入对象 1)、set方法 注入的不是以变量为准,而是以setXXX()方法为准 2)、构造函数 2.1)、按构造函数中的参数类型依次注入 2.2)、按构造函数中的参数名称注入 2.3)、按构造函数中的参数的下标注入 3)、以接口方式进行注入 9、其它类型注入 <!-- 给数组注入值 --> <property name="empName"> <list> <value>小明</value> <value>小明小明</value> <value>小明小明小明小明</value> </list> </property> <!-- 给list注入值 list 中能够有至关的对象 --> <property name="empList"> <list> <ref bean="emp2" /> <ref bean="emp1"/> <ref bean="emp1"/> <ref bean="emp1"/> <ref bean="emp1"/> <ref bean="emp1"/> <ref bean="emp1"/> </list> </property> <!-- 给set注入值 set不能有相同的对象 --> <property name="empsets"> <set> <ref bean="emp1" /> <ref bean="emp2"/> <ref bean="emp2"/> <ref bean="emp2"/> <ref bean="emp2"/> </set> </property> <!-- 给map注入值 map只有key不同,就能够装配value --> <property name="empMaps"> <map> <entry key="11" value-ref="emp1" /> <entry key="22" value-ref="emp2"/> <entry key="22" value-ref="emp1"/> </map> </property> <!-- 给属性集合配置 --> <property name="pp"> <props> <prop key="pp1">abcd</prop> <prop key="pp2">hello</prop> </props> </property> </bean> <bean id="emp1" class="com.hsp.collection.Employee"> <property name="name" value="北京"/> <property name="id" value="1"/> </bean> <bean id="emp2" class="com.hsp.collection.Employee"> <property name="name" value="天津"/> <property name="id" value="2"/> </bean> 10、Spring自动注入方式 @AutoWired set注入和构造注入有时在作配置时比较麻烦。因此框架为了提升开发效率,提供自动装配功能,简化配置。spring框架式默认不支持自动装配的,要想使用自动装配须要修改spring配置文件中<bean>标签的autowire属性。自动装配属性有5个值可选,分别表明不一样的含义。 1、byName 从Spring环境中获取目标对象时,目标对象中的属性会根据名称在整个Spring环境中查找<bean>标签的id属性值。若是有相同的,那么获取这个对象,实现关联。 整个Spring环境:表示全部的spring配置文件中查找,那么id不能有重复的。 2、byType 从Spring环境中获取目标对象时,目标对象中的属性会根据类型在整个spring环境中查找<bean>标签的class属性值。若是有相同的,那么获取这个对象,实现关联。 缺点:若是存在多个相同类型的bean对象,会出错。 若是属性为单一类型的数据,那么查找到多个关联对象会发生错误。 若是属性为数组或集合(泛型)类型,那么查找到多个关联对象不会发生异常。 三、constructor(3.x以上已不能用) 使用构造方法完成对象注入,其实也是根据构造方法的参数类型进行对象查找,至关于采用byType的方式。若是没找到则抛出异常 4、autodetect 自动选择:若是对象没有无参数的构造方法,那么自动选择constructor的自动装配方式进行构造注入。若是对象含有无参数的构造方法,那么自动选择byType的自动装配方式进行setter注入。 5、no 默认状况下,不自动装配,经过“ref”attribute手动设定。 <bean>标签的 autowire 属性,它负责自动装配<bean>标签订义 JavaBean 的属性。这样作能够省去不少配置 JavaBean 属性的标签代码,使代码整洁、美观。可是它也有负面影响,即便用自动装配以后,没法从配置文件中读懂 JavaBean 须要什么属性。自动装配存在不少不正确的装配问题,例如错误装载属性、“byType”属性和“constructor”属性对相同类型参数没法判断等。固然,将自动装配和手动装配混合使用也能解决此问题 Spring引用关联 <bean id=”名称” class=”完整类” scope=”singleton/prototype”> <property name=”完整类中的set方法名变量名” value=”值” /> <property name=”完整类中的set方法名变量名” ref=”引用SpringBean对象” /> </bean> 10、Spring 注解配置 修饰类用的 @Component 能够修饰全部类上面,如DaoImpl,ServiceImpl,Controller上面(通常用在Util,POJO) @Repository 修饰Dao @Service 修饰Service @Controller 修饰控制器 若是修用了注解,必须在applicationContext.xml中去配置扫包 <context:component-scan base-package="com.wisezone.dao,com.wisezone.service,com.wisezone.controller"> </context:component-scan> 11、Spring aop 专业名称 1)、链接点(JoinPoint) 触发点 (类初始化前,类初始化后, 方法调用前,方法调用后, 异常) 2)、切点 (pointCut) 哪些具体方法 3)、加强 (advice) 在方法 基础上,去扩展额外的功能(不修改之前类) 加强Spring有几个定位接口: BeforeAdvice(方法执行前)、 AfterReturningAdvice(方法返回以后)、 ThrowsAdvice(异常) 4)、目标对象 (Target) 实际业务逻辑类 5)、引介 (introduction) 引介是一种特殊的加强,它为类添加一些属性和方法,这样,即便一个业务类本来没有实现某个接口,经过AOP的引介功能,咱们能够动态的为该业务添加接口的实现逻辑,让业务类成为这个接口的实现类 6)、织入 (Waving) 织入是将加强添加对目标可具体链接点上的过程,AOP像一台织布机,将目标类、加强或者引介经过AOP这台织布机完美无缺的编织到一块儿。根据不一样的实现技术,AOP有三种织入的方式: (1)编译时:当一个类文件被编译时进行织入,这须要特殊的编译器才能够作的到,例如AspectJ的织入编译器 (2)类加载时:使用特殊的ClassLoader在目标类被加载到程序以前加强类的字节代码 (3)运行时:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理应该是使用了JDK的动态代理技术 Spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入 7)、代理(Proxy) 一个类被AOP织入加强后,就产生出一个结果类,它是融合了原类和加强逻辑的代理类。根据不一样的代理方式,代理类即有可能时和原类具备相同接口的类,也可能就是原类的子类,因此咱们能够采用调用原类相同的方式调用代理类 8)、切面(Aspect) 切面由切点和加强(引介)组成,它既包括了横切逻辑的定义,也包括了链接点的定义,SpringAOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的链接点中 9)、Spring支持5种类型的加强: 1.前置加强:org.springframework.aop.BeforeAdvice表明前置加强,由于Spring只支持 方法级的加强,因此MethodBeforeAdvice是目前可的的前置加强,表示在目标方法执行前 实施加强,而BeforeAdvice是为了未来版本扩展须要而定义的; 2.后置加强:org.springframework.aop.AfterReturningAdvice表明后加强,表示在目标 方法执行后实施加强; 3.环绕加强:org.aopalliance.intercept.MethodInterceptor表明环绕加强,表示在目标 方法执行先后实施加强; 4:异常抛出加强:org.springframework.aop.ThrowsAdvice表明抛出异常加强,表示在目 标方法抛出异常后实施加强; 5.引介加强:org.springframework.aop.InteoductionInterceptor表明引介加强,表示在 目标类中添加一些新的方法和属性; 这些加强接口都有一些方法,经过实现这些接口方法,在接口方法中这义横切逻辑,就能够将它们织入到目标类的方法的相应链接点的位置。 12、使用配置进行AOP代理设定 <bean id="people" class="exp1.ChinesePeople"></bean> <!-- 再配一个加强 --> <bean id="myAdvice" class="exp1.BeforeAdviceDemo"></bean> <!-- 使用Spring代理工厂产生一个代理对象 --> <bean id="sayHello" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 生成代理接口 --> <property name="proxyInterfaces" value="exp1.SayHello"></property> <property name="interceptorNames" value="myAdvice"></property> <property name="target" ref="people"></property> <!-- 变为子类 --> <property name="proxyTargetClass" value="false"></property> </bean> <property name="proxyTargetClass" value="true"></property> 生成ChinesePeolple子类 <property name="proxyTargetClass" value="false"></property> JDK动态代理,彻底不是Sayhello这个类相关的东西 13、Spring AOP execution()是最经常使用的切点函数,其语法以下图所示: execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?) execution(* com.xxxx.service..(..) ) 经过方法签名定义切点 execution(public * *(..)) 匹配全部目标类的public方法,可是不匹配Samartseller和protected void showGoods()方法。第一个*表明返回值;第二个*表明方法名;而..表明任意入参的方法 execution(* *To(..)) 匹配目标类全部以To为后缀的方法。他匹配Naïve Waiter和NaughtyWaiter的greetTo()和serveTo()方法。第一个*表明返回类型,而*To表明任意以To为后缀的方法 经过类定义切点 execution(*com.xxxx.Waiter.*(..)) 匹配Waiter接口的全部方法,它匹配NaiveWaiter和NaughtyWaiter类的greetTo()和serveTo方法。第一个*表明返回任意类型,com.xxxx.Waiter.*表明Waiter接口中的全部方法 经过类包定义切点 在类名模式串中,以“.*”表示包下的全部类,而“..*”表示包,子孙包下的全部类 execution(* com.xxxx.*(..)) 匹配com.xxxxx包下的全部类的全部方法 execution(* com.xxxx..*(..)) 匹配com.xxxx包、子孙包下全部类的全部方法,如com.xxxxx.dao、com.xxxxx.service以及com.xxxxx.user包下的全部类的全部方法都匹配,“..”出如今类名中时,后面必须跟“*”表示包、子孙包下的全部类 14、类加载器classLoader工做机制 类加载器就是寻找类或接口字节码文件进行解析并构造JVM内部对象表示的组件。在Java中,类转载器把一个类装入JVM中,须要通过如下步骤: 1.装载:查找和导入Class文件; 2.连接: 执行校验、准备和解析步骤,其中解析步骤是能够选择的: a)校验: 检查载入Class文件数据的正确性; b)准备:给类的静态变量分配存储空间; c)解析:将符号引用变成直接引用; 3.初始化:对类的静态变量、静态代码块进行初始化工做。 类装载工做是由ClassLoader及其之类负责的,ClassLoader是一个重要的Java运行时系统组件,它负责在运行时查找和装入Class字节文件。JVM在运行时会产生三个ClassLoader:跟装载器、ExtClassLoader(扩展类装载器)和AppClassLoader(系统类装载器)。其中,跟装载器不是ClassLoader的子类,它使用C++编写,所以咱们在Java中看不到它,跟装载器负责装载JRE的核心类库,如rt.jar,charsets.jar等。ExtClassLoader和AppClassLoader都是ClassLoader的子类。其中ExtClassLoader负责装载JRE扩展目录ext中的JAR类包;AppClassLoader负责装载ClassPath路径下的类包。 这三个类装载器之间存在父子层级关系,跟装载器是ExtClassLoader的父装载器,ExtClassLoader是AppClassLoader的父装载器。 15、经过AspectJ动态配置AOP import org.aspectj.lang.JoinPoint; //花费时间AOP public class SpeendAspectj { private long startTime; private long endTime; // 开始时候 public void begin(JoinPoint jp) { System.out.println("--Spring AOP监听时间开始了-----"); this.startTime=System.currentTimeMillis(); } // 方法返回之后 public void end(JoinPoint jp, Object returnValue) { this.endTime=System.currentTimeMillis(); System.out.println(jp.getTarget() + "中的" + jp.getSignature().getName() + "的方法总共花费 了:"+(endTime-startTime)+"毫秒"); } } import org.aspectj.lang.JoinPoint; public class LogAspectj { //开始时候 public void begin(JoinPoint jp){ System.out.println("--Spring AOP切面开始了-----"); System.out.println(jp.getTarget()+"中的"+jp.getSignature().getName()+"的方法"); } //方法返回之后 public void end(JoinPoint jp, Object returnValue){ System.out.println("方法执完了返回的结果是:"+returnValue); System.out.println("-----------------------------------------"); } } <!-- aop切面配置 --> <aop:config proxy-target-class="true"> <aop:pointcut expression="execution(* com.wisezone.service..*(..))" id="myPointCut" /> <aop:advisor advice-ref="myAdvice" pointcut-ref="myPointCut" /> <!-- 监听日志 --> <aop:aspect ref="log"> <aop:before method="begin" pointcut-ref="myPointCut"/> <aop:after-returning method="end" returning="returnValue" pointcut-ref="myPointCut"/> </aop:aspect> <!-- 花费时间 --> <aop:aspect ref="speedTime"> <aop:before method="begin" pointcut="execution(* com.wisezone.controller.admin..*(..))"/> <aop:after-returning method="end" returning="returnValue" pointcut="execution(* com.wisezone.controller.admin..*(..))" /> </aop:aspect> </aop:config>