课程咨询: 400-996-5531 / 投诉建议: 400-111-8989
认真做教育 专心促就业
级联操作
所谓级联操作就是说,当你进行主对象某个操作时,从对象hibernate自动完成相应操作。
比如: Department <---->Student 对象关系,我希望当我删除一个department ,那么就自动删除该部门的所有学生。
再比如: bbs项目主帖<---->回帖 , 把主帖删除,那我们就希望把该主帖的回帖自动删除,这样我们可以使用级联(cascade)操作。
案例:如何配置级联操作,当删除某个部门的时候,我们自动删除其学生.
java代码中操作:
Department department=new Department();
department.setName("业务部门");
Student stu1=new Student();
stu1.setName("小红") ;
stu1.setDept(department);
Student stu2=new Student();
stu2.setName("小明");
stu2.setDept(department);
session.save(department);
session.save(stu1);
session.save(stu2);
Department department=(Department) s.get(Department.class, 41);
s.delete(department);
save-update
java代码:
1.Department department=new Department();
department.setName("业务部门");
Student stu1=new Student();
stu1.setName("小红");
stu1.setDept(department);
Student stu2=new Student();
stu2.setName("小明");
stu2.setDept(department);
session.save(department);
虽然设置了级联操作,但是这种情况下是只会保存部门的,因为没有设置从部门到学生的反向外键引用。
可是如果在学生这边设置级联操作(学生是持有部门的外键引用的),当保存学生时,就可以将部门一并保存。
当还是从部门这边做操作时,要改成下面操作才行:
2.Department department=new Department();
department.setName("业务部门3");
Student stu1=new Student();
stu1.setName("小红");
Student stu2=new Student();
stu2.setName("小明");
Set students=new HashSet();
students.add(stu1);
students.add(stu2);
department.setStus(students); //明确使用集合关系保存
s.save(department);
说明:
① 在集合属性和普通属性中都能使用cascade
② 一般讲cascade配置在one-to-many(one的一方,比如Employee-Department),和one-to-one(主对象一方)
struts+hibernate+接口编程
这是韩顺平老师所讲hibernate案例中的一张框架图。从上往下分别是web层、业务层、dao层、hibernate层、数据库层。
在这个地方重点要学习是这个框架中的接口编程的方式,关注程序设计结构。
在框架中接口使得web层和业务层达到解耦的目的。在接口中声明方法,在业务层中将其方法实现,可是在业务层中实现的方法可能需要改变,
为了在web层中保持代码的不变性,在web层我们使用接口调用方法即可,
UsersServiceInter usersServiceInter=new UsersServiceImp();
而在我们学习使用Spring后,可以通过xml文件配置方法的方式配置 UsersServiceImp()即可,这样解耦性更高了。
还有就是定义基础接口和基础实现类。因为在MessageServiceInter和UserServiceInter中可能有公共的方法,为了增强代码的复用性,添加一个
基础接口,而只在MessageServiceInter和UserServiceInter定义自己的特有方法。同时BaseServiceImpl是一个抽象类,它可以不完全实现
BaseServiceInter中的方法,因为有些方法都需要它的继承者各自独特实现而不定义统一方法实现。
Spring(#/)是一个轻量级的Java 开发框架,同时也是轻量级的IoC和AOP的容器框架,主要是针对JavaBean的生命周期进行管理的轻量级容器,可以单独使用,也可以和Struts框架,MyBatis框架等组合使用。
IoC介绍
IoC是什么
Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。如何理解好Ioc呢?理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下:
●谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。
●为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
IoC能做什么
IoC 不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是 松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。
其实IoC对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC容器来创建并注入它所需要的资源了。
IoC很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”;即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。
那么,IoC容器到底是如何从初始化完成的BeanFactory中对Bean进行创建并初始化的呢?接下来我们就一探究竟。
源码解析
准备工作
首先写一个Spring的配置文件spring.xml,为了方便测试,这里面就只有一个名为test的bean。
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="#/schema/beans #/schema/beans/spring-beans.xsd">
编写程序入口代码,可以直接打断点进行调试。
View Code
开始解析
开始源码解析,紧接着上一节,首先进入AbstractApplicationContext.java的refresh方法,这一节我们重点来看里面的invokeBeanFactoryPostProcessors方法。
View Code
进入invokeBeanFactoryPostProcessors方法
/**
* Instantiate and invoke all registered BeanFactoryPostProcessor beans,
* respecting explicit order if given.
*
Must be called before singleton instantiation.
*/
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
打开PostProcessorRegistrationDelegate类中的invokeBeanFactoryPostProcessors方法,可以看到,这个方法里有很多内容,这里我们只分析最关键的部分。从本质上来说,该方法就是去执行BeanFactoryPostProcessor这个接口中的方法去的,上面代码注释也清楚的写到如果想先执行BeanFactoryPostProcessor这个接口的方法,必须先去实例化实现这个接口的Bean,也就是getBean这个方法。
View Code
接下来进入AbstractBeanFactory.java类中的doGetBean方法,这个方法的具体实现可以分为三个部分:
第一部分,首先先去singleton缓存中去找实例。由于我们例子中没有把我们的bean手动放入singletonObjects这个Map里面去,所以这里肯定没找到。
第二部分,然后是去获取该BeanFactory父Factory,希望从这些Factory中获取,如果该Beanfactory有父类,则希望用父类去实例化该bean,类似于JVM类加载的双亲委派机制。由于我们例子中的的Beanfactory为null,所以暂不讨论这种情况。
第三部分,这一部分是我们关注的重点,这里我们将这一大部分再分为三个小的部分来进行分析:
先将目前的bean标记为的正在创建
再获取根据beanName得到对应bean在beanfactory中的beanDefinitionMap的BeanDefinition(上一节初始化beanFactory时存入的),然后去获取这个bean依赖的bean。如果依赖的bean还没有创建,则先创建依赖的bean,进行递归调用(这就是依赖注入Dependence Injection)。如果找不到依赖,则忽略。
最后如果是单例(Spring默认是单例),则调用createBean()这个方法进行Bean的创建。
View Code
进入AbstractAutowireCapableBeanFactory.java类的createBean方法,这里面可以分为四个部分:
第一部分:确保该bean的class是真实存在的,也就是该bean是可以classload可以找到加载的
第二部分:准备方法的重写
第三部分:可以看到,这边出现了一个return,也就是说这边可以返回bean了。但看注释:Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. 这样就很清晰了,BeanPostProcessor这个接口是可以临时修改bean的,优先级高于正常实例化bean的,如果beanPostProcessor能返回,则直接返回了。
第四部分:调用doCreateBean方法开始对bean进行创建
View Code
打开doCreateBean方法,在这个方法里会做两件事:一是通过createBeanInstance这个方法创建bean,二是通过initializeBean方法初始化bean。先看看createBeanInstance这个方法里有什么玄/**
View Code
创建Bean
进入createBeanInstance方法,这块代码主要是再次对bean做安全检查并确定该bean有默认的构造函数。直接看这个方法最后一行,调用instantiateBean方法并返回方法的结果。
View Code
接着进入instantiateBean方法查看
View Code
再进入SimpleInstantiationStrategy.java的instantiate方法,我们可以看到,在这个方法里,Spring通过反射的方法根据BeanDefinition创建出Bean的对象并返回。
View Code
以上是Bean的创建,接下来我们看IoC容器是如何对Bean进行初始化的。
初始化Bean
让我们回到AbstractAutowireCapableBeanFactory.java类中的doCreateBean方法中,重点关注里面的initializeBean方法。现在bean已经被创建了,开始初始化该bean。
View Code
在这个方法中,先调用invokeAwareMethods方法用于加载相关资源(比如BeanName、BeanClassLoader、BeanFactory等资源)。
View Code
再调用applyBeanPostProcessorsBeforeInitialization方法用于构造方法执行之前再次修改Bean(BeanPostProcessor接口)。
View Code
然后通过invokeInitMethods调用自定义的初始化方法
View Code
再调用applyBeanPostProcessorsAfterInitialization方法用于构造方法执行之前再次修改Bean(BeanPostProcessor接口)。
View Code
以上就完成了创建并初始化Bean的整个过程。
通过这次源码分析,我们应该知道bean是怎么被IoC容器所创建的了,也知道IoC容器是如何去初始化spring.xml中的的bean了。我们来总结一下,整个过程最主要的就是AbstractAutowireCapableBeanFactory.java类中两个方法,一是createBeanInstance方法,用于创建Bean,二是initializeBean方法,用于初始化Bean。这两个方法需要仔细地分析和思考,如果还有不明白的地方,可以对照着Spring的源码自己动手理解一下,青岛达内it培训班小编希望能对大家有所帮助。