登陆注册
51353100000001

第1章

141、Hibernate 中 DetachedCriteria 类是做什么的?

答:DetachedCriteria 和 Criteria 的用法基本上是一致的,但 Criteria 是由 Session 的createCriteria()方法创建的,也就意味着离开创建它的 Session,Criteria 就无法使用了。 DetachedCriteria 不需要 Session 就可以创建(使用 DetachedCriteria.forClass()方法创建),所以通常也称其为离线的 Criteria,在需要进行查询操作的时候再和 Session 绑定(调用其 getExecutableCriteria(Session)方法),这也就意味着一个 DetachedCriteria 可以在需要的时候和不同的 Session 进行绑定。

142、@OneToMany 注解的 mappedBy 属性有什么作用?

答:@OneToMany 用来配置一对多关联映射,但通常情况下,一对多关联映射都由多的一方来维护关联关系,例如学生和班级,应该在学生类中添加班级属性来维持学生和班级的关联关系(在数据库中是由学生表中的外键班级编号来维护学生表和班级表的多对一关系),如果要使用双向关联,在班级类中添加一个容器属性来存放学生,并使用@OneToMany 注解进行映射,此时 mappedBy 属性就非常重要。如果使用 XML 进行配置,可以用<set>标签的inverse=“true“设置来达到同样的效果。

143、MyBatis 中使用#和$书写占位符有什么区别?

答:#将传入的数据都当成一个字符串,会对传入的数据自动加上引号;$将传入的数据直接显示生成在 SQL 中。注意:使用$占位符可能会导致 SQL 注射攻击,能用#的地方就不要使用$,写 order by 子句的时候应该用$而不是#。

144、解释一下 MyBatis 中命名空间(namespace)的作用。

答:在大型项目中,可能存在大量的 SQL 语句,这时候为每个 SQL 语句起一个唯一的标识(ID)就变得并不容易了。为了解决这个问题,在 MyBatis 中,可以为每个映射文件起一个唯一的命名空间,这样定义在这个映射文件中的每个 SQL 语句就成了定义在这个命名空间中的一个ID。只要我们能够保证每个命名空间中这个 ID 是唯一的,即使在不同映射文件中的语句 ID 相同,也不会再产生冲突了。

145、MyBatis 中的动态 SQL 是什么意思?

答:对于一些复杂的查询,我们可能会指定多个查询条件,但是这些条件可能存在也可能不存在,例如在 58 同城上面找房子,我们可能会指定面积、楼层和所在位置来查找房源,也可能会指定面积、价格、户型和所在位置来查找房源,此时就需要根据用户指定的条件动态生成 SQL 语句。如果不使用持久层框架我们可能需要自己拼装 SQL 语句,还好 MyBatis 提供了动态 SQL 的功能来解决这个问题。MyBatis 中用于实现动态 SQL 的元素主要有:- if

- choose / when / otherwise

- trim

- where

- set

- foreach

下面是映射文件的片段。

<select id=“foo“ parameterType=“Blog“ resultType=“Blog“> select * from t_blog where 1 = 1

<if test=“title != null“>

and title =#{title}

</if>

<if test=“content != null“>

and content =#{content}

</if>

<if test=“owner != null“>

and owner =#{owner}

</if>

</select>

当然也可以像下面这些书写。

<select id=“foo“ parameterType=“Blog“ resultType=“Blog“> select * from t_blog where 1 = 1

<choose>

<when test=“title != null“>

and title =#{title}

</when>

<when test=“content != null“>

and content =#{content}

</when>

<otherwise>

and owner =“owner1“

</otherwise>

</choose>

</select>

再看看下面这个例子。

<select id=“bar“ resultType=“Blog“> select * from t_blog where id in <foreach collection=“array“ index=“index“

item=“item“ open=“(“ separator=“,“ close=“)“>#{item}

</foreach>

</select>

146、什么是 IoC 和 DI?DI 是如何实现的?

答:IoC 叫控制反转,是 Inversion of Control 的缩写,DI(Dependency Injection)叫依赖注入,是对 IoC 更简单的诠释。控制反转是把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的“控制反转“就是对组件对象控制权的转移,从程序代码本身转移到了外部容器,由容器来创建对象并管理对象之间的依赖关系。IoC 体现了好莱坞原则-“Don’t call me, we will call you“。依赖注入的基本原则是应用组件不应该负责查找资源或者其他依赖的协作对象。配置对象的工作应该由容器负责,查找资源的逻辑应该从应用组件的代码中抽取出来,交给容器来完成。DI 是对 IoC 更准确的描述,即组件之间的依赖关系由容器在运行期决定,形象的来说,即由容器动态的将某种依赖关系注入到组件之中。

举个例子:一个类 A 需要用到接口 B 中的方法,那么就需要为类 A 和接口 B 建立关联或依赖关系,最原始的方法是在类 A 中创建一个接口 B 的实现类 C 的实例,但这种方法需要开发人员自行维护二者的依赖关系,也就是说当依赖关系发生变动的时候需要修改代码并重新构建整个系统。如果通过一个容器来管理这些对象以及对象的依赖关系,则只需要在类 A 中定义好用于关联接口 B 的方法(构造器或 setter 方法),将类 A 和接口 B 的实现类 C 放入容器中,通过对容器的配置来实现二者的关联。

依赖注入可以通过 setter 方法注入(设值注入)、构造器注入和接口注入三种方式来实现, Spring 支持 setter 注入和构造器注入,通常使用构造器注入来注入必须的依赖关系,对于可选的依赖关系,则 setter 注入是更好的选择,setter 注入需要类提供无参构造器或者无参的静态工厂方法来创建对象。

147、Spring 中 Bean 的作用域有哪些?

答:在 Spring 的早期版本中,仅有两个作用域:singleton 和 prototype,前者表示 Bean 以单例的方式存在;后者表示每次从容器中调用 Bean 时,都会返回一个新的实例,prototype通常翻译为原型。

补充:设计模式中的创建型模式中也有一个原型模式,原型模式也是一个常用的模式,例如做一个室内设计软件,所有的素材都在工具箱中,而每次从工具箱中取出的都是素材对象的一个原型,可以通过对象克隆来实现原型模式。

Spring 2.x 中针对 WebApplicationContext 新增了 3 个作用域,分别是:request(每次 HTTP 请求都会创建一个新的 Bean)、session(同一个 HttpSession 共享同一个 Bean,不同的 HttpSession 使用不同的 Bean)和 globalSession(同一个全局 Session 共享一个 Bean)。说明:单例模式和原型模式都是重要的设计模式。一般情况下,无状态或状态不可变的类适合使用单例模式。在传统开发中,由于 DAO 持有 Connection 这个非线程安全对象因而没有使用单例模式;但在 Spring 环境下,所有 DAO 类对可以采用单例模式,因为 Spring 利用 AOP 和 Java API 中的 ThreadLocal 对非线程安全的对象进行了特殊处理。

ThreadLocal 为解决多线程程序的并发问题提供了一种新的思路。ThreadLocal,顾名思义是线程的一个本地化对象,当工作于多线程中的对象使用 ThreadLocal 维护变量时, ThreadLocal 为每个使用该变量的线程分配一个独立的变量副本,所以每一个线程都可以独立的改变自己的副本,而不影响其他线程所对应的副本。从线程的角度看,这个变量就像是线程的本地变量。

ThreadLocal 类非常简单好用,只有四个方法,能用上的也就是下面三个方法:

- void set(T value):设置当前线程的线程局部变量的值。

- T get():获得当前线程所对应的线程局部变量的值。

- void remove():删除当前线程中线程局部变量的值。

ThreadLocal 是如何做到为每一个线程维护一份独立的变量副本的呢?在 ThreadLocal 类中有一个 Map ,键为线程对象,值是其线程对应的变量的副本,自己要模拟实现一个 ThreadLocal 类其实并不困难,代码如下所示: import java.util.Collections;

import java.util.HashMap;

import java.util.Map;

public class MyThreadLocal<T>{

private Map<Thread, T> map = Collections.synchronizedMap(new HashMap<Thread, T>());

public void set(T newValue){ map.put(Thread.currentThread(), ewValue);

}

public T get(){

return map.get(Thread.currentThread());

}

public void remove(){

map.remove(Thread.currentThread());

}

}

148、解释一下什么叫 AOP(面向切面编程)?

答:AOP(Aspect-Oriented Programming)指一种程序设计范型,该范型以一种称为切面(aspect)的语言构造为基础,切面是一种新的模块化机制,用来描述分散在对象、类或方法中的横切关注点(crosscutting concern)。

149、你是如何理解“横切关注“这个概念的?

答:“横切关注“是会影响到整个应用程序的关注功能,它跟正常的业务逻辑是正交的,没有必然的联系,但是几乎所有的业务逻辑都会涉及到这些关注功能。通常,事务、日志、安全性等关注就是应用中的横切关注功能。

150、你如何理解 AOP 中的连接点(Joinpoint)、切点(Pointcut)、增强(Advice)、引介(Introduction)、织入(Weaving)、切面(Aspect)这些概念?

答:

连接点(Joinpoint):程序执行的某个特定位置(如:某个方法调用前、调用后,方法抛出异常后)。一个类或一段程序代码拥有一些具有边界性质的特定点,这些代码中的特定点就是连接点。Spring 仅支持方法的连接点。

切点(Pointcut):如果连接点相当于数据中的记录,那么切点相当于查询条件,一个切点可以匹配多个连接点。Spring AOP 的规则解析引擎负责解析切点所设定的查询条件,找到对应的连接点。

增强(Advice):增强是织入到目标类连接点上的一段程序代码。Spring 提供的增强接口都是带方位名的,如:BeforeAdvice、AfterReturningAdvice、ThrowsAdvice 等。很多资料上将增强译为“通知”,这明显是个词不达意的翻译,让很多程序员困惑了许久。

说明: Advice 在国内的很多书面资料中都被翻译成“通知“,但是很显然这个翻译无法表达其本质,有少量的读物上将这个词翻译为“增强“,这个翻译是对 Advice 较为准确的诠释,我们通过 AOP 将横切关注功能加到原有的业务逻辑上,这就是对原有业务逻辑的一种增强,这种增强可以是前置增强、后置增强、返回后增强、抛异常时增强和包围型增强。

引介(Introduction):引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过引介功能,可以动态的未该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。

织入(Weaving):织入是将增强添加到目标类具体连接点上的过程,AOP 有三种织入方式:①编译期织入:需要特殊的 Java 编译期(例如 AspectJ 的 ajc);②装载期织入:要求使用特殊的类加载器,在装载类的时候对类进行增强;③运行时织入:在运行时为目标类生成代理实现增强。Spring 采用了动态代理的方式实现了运行时织入,而 AspectJ 采用了编译期织入和装载期织入的方式。

切面(Aspect):切面是由切点和增强(引介)组成的,它包括了对横切关注功能的定义,也包括了对连接点的定义。

补充:代理模式是 GoF 提出的 23 种设计模式中最为经典的模式之一,代理模式是对象的结构模式,它给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。简单的说,代理对象可以完成比原对象更多的职责,当需要为原对象添加横切关注功能时,就可以使用原对象的代理对象。我们在打开 Office 系列的 Word 文档时,如果文档中有插图,当文档刚加载时,文档中的插图都只是一个虚框占位符,等用户真正翻到某页要查看该图片时,才会真正加载这张图,这其实就是对代理模式的使用,代替真正图片的虚框就是一个虚拟代理; Hibernate 的 load 方法也是返回一个虚拟代理对象,等用户真正需要访问对象的属性时,才向数据库发出 SQL 语句获得真实对象。

下面用一个找枪手代考的例子演示代理模式的使用:

/**

*参考人员接口

*/

public interface Candidate {

/**

答题

*/

public void answerTheQuestions();

}

/**

*懒学生

*@author 骆昊

*

*/

public class LazyStudent implements Candidate {

private String name;//姓名

public LazyStudent(String name){

this.name = name;

}

@Override

public void answerTheQuestions(){

//懒学生只能写出自己的名字不会答题

System.out.println(“姓名:“+ name);

}

}

/**

枪手

@author 骆昊

*/

public class Gunman implements Candidate { private Candidate target;//被代理对象

public Gunman(Candidate target){

this.target = target;

}

@Override

public void answerTheQuestions(){

//枪手要写上代考的学生的姓名

target.answerTheQuestions();

//枪手要帮助懒学生答题并交卷

System.out.println(“奋笔疾书正确答案“);

System.out.println(“交卷“);

}

}

public class ProxyTest1 {

public static void main(String[] args){

Candidate c = new Gunman(new LazyStudent(“王小二“)); c.answerTheQuestions();

}

}

说明:从 JDK 1.3 开始,Java 提供了动态代理技术,允许开发者在运行时创建接口的代理实例,主要包括 Proxy 类和 InvocationHandler 接口。下面的例子使用动态代理为 ArrayList 编写一个代理,在添加和删除元素时,在控制台打印添加或删除的元素以及 ArrayList 的大小:

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.List;

public class ListProxy<T> implements InvocationHandler { private List<T> target;

public ListProxy(List<T> target){

this.target = target;

}

@Override

public Object invoke(Object proxy, Method method, Object[] args)

throws Throwable {

Object retVal = null;

System.out.println(“[“+ method.getName()+“:“+ args[0]+“]“); retVal = method.invoke(target, args); System.out.println(“[size=“+ target.size()+“]“); return retVal;

}

}

import java.lang.reflect.Proxy;

import java.util.ArrayList;

import java.util.List;

public class ProxyTest2 {

@SuppressWarnings(“unchecked“)

public static void main(String[] args){ List<String> list = new ArrayList<String>(); Class<?> clazz = list.getClass();

ListProxy<String> myProxy = new ListProxy<String>(list); List<String> newList =(List<String>)

Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), myProxy);

newList.add(“apple“);

newList.add(“banana“);

newList.add(“orange“);

newList.remove(“banana“);

}

}

说明:使用 Java 的动态代理有一个局限性就是代理的类必须要实现接口,虽然面向接口编程是每个优秀的 Java 程序都知道的规则,但现实往往不尽如人意,对于没有实现接口的类如何为其生成代理呢?继承!继承是最经典的扩展已有代码能力的手段,虽然继承常常被初学者滥用,但继承也常常被进阶的程序员忽视。CGLib 采用非常底层的字节码生成技术,通过为一个类创建子类来生成代理,它弥补了 Java 动态代理的不足,因此 Spring 中动态代理和 CGLib 都是创建代理的重要手段,对于实现了接口的类就用动态代理为其生成代理类,而没有实现接口的类就用 CGLib 通过继承的方式为其创建代理。

同类推荐
  • 总统先生的秘书

    总统先生的秘书

    一个女孩叫蓝心淼在18岁那一年父亲因赌博不想连累蓝心淼和她母亲离她们而去,母亲也被一场突如期来的车祸而离世,她便被小姨收养了。可她正因如此努力学习进了A国的外交部,最后居然被刚上任的年仅24岁的总统选为贴身秘书翻译员,后来居然成为了总统夫人......
  • 一碗大肉面

    一碗大肉面

    本文讲述了主人公的一段青春记忆,游离于主流学院的‘自考’学生,混迹于学校和社会之间。财富美女、兄弟情深,有成功的喜悦、失败的无奈。希望唤醒那一代人的青春记忆!
  • 阴疯

    阴疯

    阴疯非仙非道非佛非灵。阴疯,民间称为某种精神病。《阴疯》讲的是二个女孩成阴疯记,故事的女主角历多事成阴疯,女二号早早成疯。故事中各方面为图一利,使手段致疯。其中内外各势力力角的故事穿插其中,影出社会一面。
  • 西阳沟纪事

    西阳沟纪事

    通过主人公毕业后参与中国铁路大动脉南昆铁路的建设,再现当年中国工程建设者无私的情怀,和那些在可歌可泣的感人事迹。小说所有人都是平凡而普通的建设者,但他们却用汗水共同谱写了不一样的青春之歌!
  • 逆转人生路

    逆转人生路

    看主角怎么从一个混蛋走到一个世界的巅峰,看主角怎么玩转人生的按钮,看主角......反正就是看主角不要看我就是啦
热门推荐
  • 超神狗策划

    超神狗策划

    这是一个声称自己是系统亲爹的家伙,誓要砍了龟儿子的奇葩故事。卡牌侠客+伪君子+血袈裟+阉刀=岳不群卡牌兽人+狂躁+再生+伽马射线=伪浩克灭霸干爹、麻衣神相、诸天强者,通通都到碗里来。组合最强英雄,玩家立正站好,哥的敌人是NPC裙:237067872
  • 致那一份青春

    致那一份青春

    如花美眷,也抵不过似水流年,每个人,都有属于自己的那一份独特的青春记忆。小说通过描述一个在普通的小女生在重点初中、重点班级学习、生活点点滴滴,来记录这份青春,每天不断通过自己努力,为自己加油,不复青春。对每一个明天恰到好处的充满期待!
  • 丫头等等朕

    丫头等等朕

    仇人见面,分外眼红。这对夫妻见面。。。。相看两厌。某亦:“丫头,你看朕帅不帅?”念念【淡定的甩个白眼】:“你能很帅。”没等那人狂笑,念念又道:“母猪都能开飞机。”某人一脸黑线。。。。。。。
  • 他的专属恶女

    他的专属恶女

    我在下一个路口等他转身。等他救赎我。等他不要离开我。等他许我一世白头的誓言。雨摇曳,湿了我眼。因为我明白。是我,辜负了这场盛世幸福。
  • 惹上霸道王爷难为妃

    惹上霸道王爷难为妃

    被炸死就算了,还穿到一个傻子身上,原来还是一个美人!关心疼爱她的一家子,紧追不舍的美男,啊呀,其实她想多泡几个帅哥呀。“王爷,王妃说要给你做吃的。”书桌前的男人咻的冲出去,“娘子,这种小事还是为夫来吧。”
  • 幽冥仙君

    幽冥仙君

    无根树,花正偏,离了阴阳道不全。金隔木,汞隔铅,孤阴寡阳各一边。世上阴阳男配女,生子生孙代代传。顺为凡,逆为仙,只在中间颠倒颠。……这是一个写作“鬼仙人”,读作“可止小儿夜啼”的故事。(《幽冥仙君》书友群:476994705)
  • 贪恋红尘三千尺

    贪恋红尘三千尺

    本是青灯不归客,却因浊酒恋红尘。人有生老三千疾,唯有相思不可医。佛曰:缘来缘去,皆是天意;缘深缘浅,皆是宿命。她本是出家女,一心只想着远离凡尘逍遥自在。不曾想有朝一日唯一的一次下山随手救下一人竟是改变自己的一生。而她与他的相识,不过是为了印证,相识只是孽缘一场。
  • 不得不放手

    不得不放手

    人生总有选多选择,适当的时候要学会放手。有一颗善良体贴的心远比有漂亮的外表更重要,美貌只能维持一时,内在美才能让你走的更远,更坦然......
  • 产后健康百科

    产后健康百科

    本书是以新妈妈的产后健康和宝宝的正确护养为基础,详解产后日常生活中新妈妈的康复重点和宝宝的护养重点,包括产后生活、健康坐月子、产后饮食和新生儿护养四大重点内容,让新妈妈能够对自己身体出现的问题以及宝宝护养时出现的问题有个科学的认识,让新妈妈顺利度过身体恢复的每个阶段。
  • 天行

    天行

    号称“北辰骑神”的天才玩家以自创的“牧马冲锋流”战术击败了国服第一弓手北冥雪,被誉为天纵战榜第一骑士的他,却受到小人排挤,最终离开了效力已久的银狐俱乐部。是沉沦,还是再次崛起?恰逢其时,月恒集团第四款游戏“天行”正式上线,虚拟世界再起风云!