Spring 技术总结
一、spring体系结构
1、Spring Core Spring的核心,管理bean,提供依赖注入
2、Spring Context Spring的上下文,BeanFactory的一个子接口
3、Spring AOP Spring的面向方面编程
4、Spring DAO Spring对JDBC的封装
5、Spring ORM Spring对ORM框架的支持(hibernate ...)
6、Spring Web Spring对Web MVC框架的支持(struts ...)
7、Spring Web MVC Spring自身的MVC框架
二、使用Spring的实现步骤
1、创建项目并添加Spring所需jar包。(spring.jar,log4j的日志jar包,还有jakarta-commons的相关jar包)
2、创建log4j.properties文件,用来控制日志输出。
3、新建一个javaBean 。其中的属性需要定义set和get方法 。
4、创建applicationContext.xml文件,这是Spring的配置文件,可以定义上述bean以及它的属性。
5、新建一个java类,通过ApplicationContext接口的一个实现类ClassPathXmlApplicationContext读取pplicationContext.xml文件:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
然后就可以使用context的getBean(String id)方法获得指定类的实例:
HelloSping hellospring = (HelloSping)context.getBean("helloSpring");
其中helloSpring就是配置文件中bean的id 。
<bean id="helloSpring" class="com.pb.HelloSping">
接下来就可以调用获得类的方法,通过配置文件注入所需要的类,从而实现松耦合。
三、Spring框架涉及到的两种主要的设计模式
1、工厂模式 创建bean的功能由Spring工厂完成,不需要调用者创建。根据要求返回适合的类实例,工厂内的类实例其实是实现相同接口或父类的实例。
2、单态模式 对于相同id的bean的请求都返回同一个bean实例,减少系统对创建和销毁bean的开销 。
(1)把类实例设置为静态属性
(2)所有构造方法设置成私有的
(3)提供一个静态的方法获取实例属性
四、BeanFactory介绍
1、BeanFactory的作用
配置、创建以及管理bean对象(但是bean是存在于spring容器中,BeanFactory是spring容器中的一个工具)
维持Bean对象之间的依赖关系
负责Bean对象的生命周期
2、BeanFactory通常有如下方法
(1)containsBean(String beanname) //判断spring配置文件中是否有id为beanname的bean
(2)Object getBean(String beanname) //获得Bean实例
3、BeanFactory常用实现类
(1)XmlBeanFactory
(2)ApplicationContext(是BeanFactory的子接口,实现了BeanFactory的全部功能,j2ee项目推荐使用,其常用的实现类是FileSystemXmlApplicationContext和ClassPathXmlApplicationContext)
(2.1)该接口还实现了国际化的支持
(2.2)通过getResource(String resourcename)可以轻松获得Resource对象
(2.3)事件传播(自行查阅资料)
(2.4)多配置文件的加载(三种方式)
(2.4.1).第一种,使用数组参数
ApplicationContext contex=new ClassPathXmlApplicationContext(new String["a1.xml","a2.xml"]);
(2.4.2).第二种,只用通配符
ApplicationContext contex=new ClassPathXmlApplicationContext("a*.xml");
但此种方法只对文件系统中的xml文件有效,针对jar包中的无效
(2.4.3).第三种,引入
ApplicationContext contex=new ClassXmlApplicationContext("a1.xml");
在a1.xml中
<import resource="a2.xml"/> 执行resource路径为相对a1.xml的路径
五、ApplicationContext.xml结构分析
1、根节点<beans></beans>
2、根节点中可以包含多个<bean></bean>节点。
3、<bean>节点中有两个重要属性id(name)和class,示例如下:
<bean id="helloSpring" class="com.pb.HelloSping">
<property name="str">
<value>军人</value>
</property>
<property name="man">
<value>林冲</value>
</property>
</bean>
4、Bean在spring容器中有两种行为
(1)singleton 返回唯一实例
(2)non-singleton 每次请求创建新的实例
5、使用getBean(String beanid)获取bean的实例时,如果查找不到id为beanid的bean时,就会查找name为beanid的bean,如果还是查找不到就会抛出异常。但是当配置文件中的bean既没有id属性,也没有name属性,只有class属性,这时我们可以通过类的全限定名获得bean,示例如下:
<bean class="com.pb.HelloSping">
</bean>
HelloSpring hello = Context.getBean("com.pb.HelloSping");
6、指定bean的别名
<alias name="fromname" alias="toname" />
fromname指代的是bean的id或者name,toname指代的是为该bean指定的代号。该代号也可以用于getBean方法获得bean。
六、Bean的管理
1、对于基本数据类型和String类型的属性可以使用以下语句进行配置
<property name="name">
<value>小明</value>
</property>
<property name="age">
<value>13</value>
</property>
针对以上类型的属性,都是以String的方法注入,然后由Spring自行转换为对应的类型。
2、对于属性为对象类型的,例如Beans中其它bean类型的属性,需要使用以下配置
<property name="man">
<ref bean="man" />
</property>
其中ref中的bean属性填入引用的bean的name或者id,除了使用bean属性之外还可以使用local属性,它们之间的区别是,bean属性可以引用不在同一个配置文件中的bean对象
3、对于集合元素类型属性的配置方法如下
(1)List list中可以注入普通类型的值,也可以注入对象类型的值,也可以引用其它bean
<property name="lists">
<list>
<value><value>
<bean class="com.pb.SpringMan">
....
</bean>
.....
<ref bean="" />
</list>
</property>
(2)Map
<property name="maps">
<map>
<entry key="key1">
<value>value1</value>
</entry>
<entry key="key2">
<value>value2</value>
</entry>
<entry key="key3">
<value>value3</value>
</entry>
</map>
</property>
(3)Props
<property name="props">
<props>
<prop key="key1">value1</prop>
<prop key="key2">value2</prop>
<prop key="key3">value3</prop>
</props>
</property>
(4)Set set中可以注入普通类型的值,也可以注入对象类型的值,也可以引用其它bean
<property name="sets">
<set>
<value><value>
<bean class="com.pb.SpringMan">
....
</bean>
.....
<ref bean="" />
</set>
</property>
4、bean的autowire属性有以下三个值
(1)、no(默认) 不使用自动绑定,bean 通过ref进行绑定
(2)、byName 根据属性的名称进行自动绑定
(3)、byType 根据属性的类型进行自动绑定
假如有一个类A,它包含一个属性b,该属性是对象类型的(类B),那么在配置文件中定义bean的时候就是如下这样:
<bean id="b" class="B"></bean>
<bean id="a" class="A" >
<property name="b">
<ref bean="b" />
</property>
</bean>
这就是默认情况下的配置,即autowire="no" ,如果设置autowire="byName ",则不需要使用<property>来指定,Spring会通过属性名来寻找匹配的id的bean注入到属性中,通过设置autowire="byType " 则会通过属性的类型来寻找匹配的bean,如果找到多个匹配类型的bean则会抛出异常。
5、bean的作用域(设置bean的Scope属性)
(1)singletion 默认的,每个IOC容器只创建一个Bean实例
(2)prototype每次请求创建一个Bean实例
(3)request每次http请求创建一个实例
(4)session每次会话创建一个实例
(5)globalsession每个全局Http请求创建一个实例
6、Bean注入依赖关系后和销毁前的管理
(1)Bean注入依赖关系后
(1.1)通过指定init-method属性可以在注入依赖关系后执行一些操作,例如在Bean类中定义了一个init()方法,然后可以在配置文件对应的bean元素中添加init-method="init" 。
(1.2)通过创建类实现InitializingBean接口,然后实现里面的afterPropertiesSet()方法也可以实现上述的效果,使用该方法需要在配置文件中添加该类相应的bean,但是不推荐使用该方法,因为会造成与spring接口耦合。
(2)Bean销毁前
(2.1)通过指定destroy-method属性可以在销毁bean前执行一些操作
(2.2)通过创建类实现DisposeableBean接口,然后实现里面的destroy()方法也可以实现上述的效果
7、Bean配置的parent属性
(1)使用parent属性可以继承其它Bean的配置,可以把某些Bean的相同配置独立出来做成一个Bean,然后其它Bean继承该Bean,可以减少工作量,提高开发效率。
<bean id="women" class="com.pb.SpringWomen" parent="man1">
8、Bean注入方式
(1)属性注入 使用property
(2)构造方法注入 使用带参的构造方法,首先需要在类中定义相应的构造方法,然后需要在配置文件中指定构造方法参数的值如下:
<bean id="women1" class="com.pb.SpringWomen">
<constructor-arg index="0">
<value>朴信惠</value>
</constructor-arg>
<constructor-arg index="1">
<value>27</value>
</constructor-arg>
</bean>
9、针对Bean类的相关Aware接口
(1)BeanNameAware 实现该接口的Bean类可以通过实现该接口的一个方法:void setBeanName(String BeanId) 获得配置文件中对应Bean的Id或者name 。
(2)BeanFactoryAware 实现该接口的Bean可以通过对应的setBeanFactory方法(与上类似)获得BeanFactory实例
(3)ApplicationContextAware 实现该接口的Bean可以通过对应的setApplicationContext方法(与上类似)获得ApplicationContext实例
10、Bean的高级管理
(1)实现BeanPostProcessor(Bean后处理器)接口的Bean可以在Spring创建Bean实例之前和创建之后执行一些操作,需要实现该接口的两个方法:Object postProcessAfterInitialization(Object Bean,String BeanName) 和 Object postProcessBeforeInitialization (Object Bean,String BeanName) ,这两个方法有两个参数Bean为容器创建的Bean实例,BeanName是Bean配置中的id或者name,实现后一个方法的之后需要返回Bean,否则会出现空指针异常 。
(2)BeanFactoryPostProcessor(容器后处理器)可以在BeanFactory读取配置文件后,实例化Bean之前执行一些操作,需要实现以下方法
void postProcessBeanFactory(ConfigurableListableBeanFactory Congifg) 。
针对以上接口,如果是通过ApplicationContext建立的容器,只需要在配置文件中添加实现该接口的相应的Bean,容器就会自动识别并执行,而如果是通过BeanFactory建立的容器,则需要手动注册
(3)PropertyPlaceholderConfigurer 属性占位符配置器 是BeanFactoryPostProcessor的实现类,该类有如下作用:
(3.1)读取properties配置文件
(3.2)不需要打开Spring配置文件的情况下,也可以把properties配置文件中的某些值引入到Spring配置文件中
(3.3)可以配置多个配置文件信息
直接在Spring配置文件中添加相应的Bean配置即可使用
<bean id="propertypConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>xxxx.properties</value>
<value>xxxx.properties</value>
.......
</list>
</property>
</bean>
在Spring配置文件中使用properties定义的值可以使用${key} 。使用Beanfactory创建的容器使用这些外部配置,需要在执行以下语句才能使用: //读取配置文件
XmlBeanFactory context = new XmlBeanFactory(new FileSystemResource("src/applicationContext.xml"));
//创建PropertyPlaceholderConfigurer 实例
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
//读取外部配置文件
cfg.setLocation(new FileSystemResource("src/jdbc.properties"));
//加载到Spring配置文件中
cfg.postProcessBeanFactory(context);
(4) PropertyOverrideConfigurer 属性占位符配置器 ,使用该配置器加载的配置文件(.properties)的内容会覆盖Spring配置文件中的内容,其配置文件格式如下
BeanName.property = value
例如有如下Bean:
<bean id="man" class="com.pb.SpringMan">
<property name="name">
<value>小明</value>
</property>
<property name="age">
<value>13</value>
</property>
</bean>
则对应的properties配置文件格式是
man.name=王力宏
这样当在Spring中使用以下语句加载上述外部配置文件时就会覆盖原来的id为man的bean的name属性的值:
<bean id="propertypConfigurer" class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
<property name="locations">
<list>
<value>xxxx.properties</value>
<value>xxxx.properties</value>
.......
</list>
</property>
</bean>
(5)自定义属性编辑器 ,由于某些特殊类型的属性值可能不能被正确转换,例如日期类型,所以需要自定义属性编辑器来解决这类问题
(5.1)、自定义属性编辑器需要继承PropertyEditorSupport类,并重写其setAsText(String text)方法,其中参数text代表需要转换的值。实现该方法时注意需要使用this.setValue(Object o )来完成转换后的内容赋值,否则转换了也没有用。参考代码如下:
public void setAsText(String arg0) throws IllegalArgumentException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
try {
this.setValue(sdf.parse(arg0));
} catch (ParseException e) {
e.printStackTrace();
}
}
(5.2)、在Spring配置文件中添加如下配置:
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date">
<bean class="com.pb.ParseDate">
<property name="format">
<value>yyyy-MM-dd</value>
</property>
</bean>
</entry>
</map>
</property>
</bean>
上述配置起作用的关键是<entry key="java.util.Date">,这个相当于过滤器,把属性类型为java.util.Date的属性配置都使用com.pb.ParseDate进行处理 。
11、AOP基本概念
(1)AOP全称是 aspect oriented programming 面向方面编程
(2)AOP的作用是把代码中的公共功能部分抽离处理,减少代码的复杂度,使得代码作用统一,例如对于异常的处理等功能就可以抽取出来。
(3)AOP术语:
Aspect 当需要时,把它放到应用程序之上,当不需要时,把它从应用程序中抽离
Advice 是Aspect的具体实现
Joinpoint Aspect在应用程序执行时加入业务流程的时机
Pointcut 指定某个Aspect在哪些Pointcut时被穿插到应用程序之上
Target 一个advice被应用的对象或目标对象
Instruction 为已编译完成的类,在执行时动态加入一些方法,而不用修改或者增加任何代码
Weave 被应用到对象之上的过程
(4)Spring的AOP技术使用Java代码实现,而不是AOP语言
(5)Spring不支持属性成员的Joinpoint,因为这会影响Java的封装特性。
12、Advice的具体应用
(1)MethodBeforeAdvice接口 实现该接口,重写该接口的void before(Method arg0, Object[] arg1, Object arg2)方法,就可以实现在指定的bean的所有方法执行之前都执行一次before方法。具体使用步骤如下:
(1.1)、定义Bean接口(必须)
(1.2)、建立实现Bean接口及其方法的bean
(1.3)、建立实现MethodBeforeAdvice接口的类,以及重写before方法。
(1.4)、在Spring配置文件中加入以下配置:
<bean id="before" class="com.pb.MethodBefordAdvice" /> <!--实现了MethodBeforeAdvice接口的类-->
<bean id="he" class="com.pb.Hello" /> <!--目标bean-->
<bean id="helloproxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- ProxyFactoryBean代理类-->
<property name="proxyInterfaces">
<value>com.pb.IHello</value>
</property>
<property name="target">
<ref bean="he"></ref>
</property>
<property name="interceptorNames">
<list>
<value>before</value>
</list>
</property>
</bean>
(1.5)、使用代理类的bean的id获得IHello接口,然后调用Hello的方法:
IHello h = (IHello)context.getBean("helloproxy");
h.sayHello("陈豪");
h.sayGoodBye("陈豪");
--------------运行结果------------------
执行sayHello方法前!
你好:陈豪
执行sayHello方法前!
陈豪,再见!!
(2)AfterReturningAdvice接口 其中的方法是void afterReturning(Object arg0, Method arg1, Object[] arg2,Object arg3) throws Throwable
作用与上相反,配置方法与上类似。
(3)MethodInterceptor接口,其中的方法是Object invoke(MethodInvocation arg0) throws Throwable ,实现该接口可以同时实现上述两个接口的功能,即在执行方法前和方法后执行一些操作。该方法需要返回一个Object对象,使用MethodInvocation 对象(即arg0)的proceed()方法可以获得,调用该方法proceed()相当于把执行权交回给目标类的方法,所以在调用该方法前的代码属于BeforeAdvice,而在调用该方法后的方法属于AfterAdvice ,该接口也称为AroundAdvice。
(4)ThorwsAdvice 接口 该接口没有定义任何方法,我们可以自行创建,方法名和参数不能够随便,以下提供了可供参考的方法:
public void afterThrowing(Exception ex)
public void afterThrowing(RemoteException)
public void afterThrowing(Method method, Object[] args, Object target, Exception ex)
public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)
以上方法会在目标bean发生异常的时候执行。
(5)基于XML Schema 创建Spring Advice
使用该方法创建的Advice不需要实现特定的接口,可以直接在Spring配置文档中配置好了即可使用,但是要满足以下要求:
(5.1)、配置文件中需要使用<aop>标签,所以需要在XML文件头中添加相应配置:
增加命名空间:xmlns:aop="http://www.springframework.org/schema/aop"
增加xsi:schemaLocation配置:http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
(5.2)、<aop:config>配置格式如下所示:
<bean id="hello" class="com.pb.Hello" />
<bean id="advicer" class="com.pb.HelloAdvicer" />
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* c*..H*.say*(..)) and args(user)"/>
<aop:aspect ref="advicer">
<aop:before pointcut-ref = "pointcut" method="beforeAdvice(java.lang.String)" arg-names="user"/>
<aop:after pointcut="execution(* com.pb..*.sayHello(..))" method="afterAdvice"/>
<aop:after-returning pointcut="execution(* com.pb..*.sayHello(..))"
method="afterReturningAdvice"
arg-names="value"
returning="value"/>
<aop:after-throwing pointcut="execution(* com.pb..*.sayHello(..))"
method="afterThrowingAdvice"
arg-names="e"
throwing="e"/>
<aop:around pointcut="execution(* com.pb..*.sayHello(..))"
method="aroundAdvice"
/>
</aop:aspect>
</aop:config>
(5.2.1)其中aop:pointcut 为切入点 其属性expression需要使用execution表达式,以这个(execution(* c*..H*.say*(..))为例说明,第一个*固定(不知道为什么),然后c*..代表以c开头类的包名可以直接使用*..代表任意包,第三个H*.代表以H开头的类名或接口名,可以直接使用*.代表任意类或接口,第三个部分是say*表示以say开头的方法名,不能直接使用*代表方法名,第四部分是(..)代表具有任意参数的方法,还可以使用具体类型(String),或者多个参数(String,Integer,..),还可以使用自定义类型(com.pb.Hello) 。可以使用简单模式实现上述效果(execution(* say*(..))
(5.2.2)<aop:aspect ref="advicer"> 中ref属性指代Advice类的实现类
(5.2.3)<aop:aspect> </aop:aspect>包含的配置就是各种对应的Advice方法。具体配置参考api文档 。
(5.2.4)Advice的实现类定义如下:
public class HelloAdvicer {
public void beforeAdvice(String user){
System.out.println("执行sayhello方法前:"+user);
}
public void afterAdvice(){
System.out.println("执行sayhello方法后");
}
public void afterReturningAdvice(){
System.out.println("这是Advicer类中的afterReturningAdvice方法");
}
public void afterThrowingAdvice(){
System.out.println("这是Advicer类中的afterThrowingAdvice方法");
}
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("这是Advicer类中的aroundAdvice方法");
return pjp.proceed();
}
}
(5.2.5)程序入口关键的代码如下:
ApplicationContext context = new FileSystemXmlApplicationContext("src/applicationContext.xml");
IHello hello = (IHello)context.getBean("hello");
hello.sayHello("朴信惠");
-----------运行结果---------------
执行sayhello方法前:朴信惠
这是Advicer类中的aroundAdvice方法
朴信惠,你好
执行sayhello方法后
这是Advicer类中的afterReturningAdvice方法
(6)基于注解Annotation的Advice 使用注解实现的Advice也是不需要实现特定接口就可以实现上述的Advice功能,但是需要满足以下条件:
(6.1)建立一个普通类作为Advice,添加注解如下:
@Aspect
public class AspectJ {
@Pointcut("execution(* Hello.sayHello(..))")
public void log(){
}
@Before(value="log()")
public void startLog(){
System.out.println("访问方法前!!");
}
@After(value="log()")
public void endLog(){
System.out.println("访问方法后!!");
}
}
其中@Aspect表示这是一个Aspect类,@Pointcut定义切入点,@Before定义前方法,@After定义后方法
(6.2)配置文件中需要添加如下语句(注意使用到aop标签的要求):
<aop:aspectj-autoproxy />
<bean id="aspectj" class="com.pb.AspectJ" />
<bean id="hello" class="com.pb.Hello" />
(6.3)程序入口关键代码:
IHello h = (IHello)context.getBean("hello");
h.sayHello("陈豪");
h.sayGoodBye("陈豪");
------------运行结果------------
访问方法前!!
你好:陈豪
访问方法后!!
陈豪,再见!!
(7)结合pointcut和Advice的实现类,使用该方法配置是为了更加精确的指定切入advice的方法,是对前四种方法的一个功能加强
(7.1)NameMatchMethodPointcutAdvisor 最基本的PointcutAdvicer
(7.1.1)在Spring配置文件中加入以下配置即可实现功能:
<bean id="NameMatch" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="mappedName">
<value>say*</value> <!--可以指定只有say开头的方法调用advice-->
</property>
<property name="advice">
<ref bean="advicer"/> <!--此处指定使用的Advice(before,after,around,throw)-->
</property>
</bean>
---------------以下是对代理bean的修改-----------
<bean id="helloproxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>com.pb.IHello</value>
</property>
<property name="target">
<ref bean="hello"></ref>
</property>
<property name="interceptorNames">
<list>
<value>NameMatch</value> <!--此处使用上述配置中的bean的id-->
</list>
</property>
(7.1.2)程序入口代码不变
(7.2)RegexpMethodPointcutAdvisor 使用正则表达式来定义Pointcut
(7.2.1)与上述实现步骤类似,但是配置文件中需要作出下面的修改:
(7.2.2)正则表达式语法:
表1.常用的元字符
代码 说明
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线或汉字
\s 匹配任意的空白符
\d 匹配数字
\b 匹配单词的开始或结束
^ 匹配字符串的开始
$ 匹配字符串的结束
表2.常用的限定符
代码/语法 说明
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
(7.2.3)正则表达式示例:^.*(say)+.*$ 这个代表targe中say开头的方法
(8)动态代理实现AOP 使用该方法可以不配置Spring配置信息,即可实现AOP
(8.1)需要实现InvocationHandler接口以及实现其invoke方法 。关键代码如下:
private Object targe; //targe指代的是目标类的实例
//获取代理类实例的方法
public Object bind(Object targe){
this.targe = targe;
return Proxy.newProxyInstance(targe.getClass().getClassLoader(),
targe.getClass().getInterfaces(), this);
}
//实现AOP的核心方法
@Override
public Object invoke(Object arg0, Method method, Object[] arg2)
throws Throwable {
Object result = null;
System.out.println("目标方法前执行");
result = method.invoke(targe, arg2);
System.out.println("目标方法后执行");
return result;
}
(8.2)程序入口核心代码:
LogHandler log = new LogHandler();
IHello he = (IHello)log.bind(new Hello()); //Hello是实现IHello接口的实现类
he.sayHello("朴信惠");
--------------执行结果-------------------
目标方法前执行
朴信惠,你好
目标方法后执行
AOP编程小结:目前学习的几种AOP编程实现几乎都是依靠代理类的 。
13、使用Spring实现JDBC操作数据库
准备条件:
Spring所需jar包,Oracle14.jar
(1)通过Spring配置建立一个数据源类型的Bean,通过引用该配置可以为DAO注入DataSource属性,在该配置中需要指定数据库驱动,url,用户名和密码等信息,示例如下:
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>oracle.jdbc.driver.OracleDriver</value>
</property>
<property name="url">
<value>jdbc:oracle:thin:@localhost:1521:orcl</value>
</property>
<property name="username">
<value>zzl</value>
</property>
<property name="password">
<value>zzl</value>
</property>
</bean>
(2)建立一个接口IUserDao ,并建立一个用于操作数据库的方法,为什么需要定义接口而不直接使用建立类,当然直接建立类也是可以实现该操作的,但是定义接口可以使得业务类与Dao类解耦,而业务类只与接口耦合,那样只需要修改配置文件就可以有多种实现,示例如下:
public interface IUserDao{
public void find();
}
(3)建立一个类实现IUserDao接口,其中需要定义一个DataSource类型的属性以及其set方法,用于注入DataSource使用,同时实现接口的方法,示例如下:
public class UserDaoImpl implements IUserDao{
private DataSource source; //Spring的注入不会直接注入到Bean的属性,所以该属性不是必须的
public DataSource getSource() {
return source;
}
//该方法才是Spring注入的核心,Spring是把注入的内容放到方法的参数了,要怎么利用参数是我们决定的
public void setSource(DataSource source) {
this.source = source;
}
@Override
public void find() {
Connection conn = null;
PreparedStatement statement=null;
ResultSet rs=null;
try {
conn = source.getConnection();
statement = conn.prepareStatement("select * from house_type");
rs = statement.executeQuery();
while(rs.next()){
System.out.println(rs.getInt("id")+":"+rs.getString(2));
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
if(rs!=null){
rs.close();
}
if(statement!=null){
statement.close();
}
if(conn!=null){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
(4)编写程序入口代码,示例如下:
ApplicationContext context = new FileSystemXmlApplicationContext("src/applicationContext.xml");
IUserDao dao = (IUserDao)context.getBean("dao");
dao.find();
(5)编写Spring配置文件:
<bean id="dao" class="com.pb.UserDaoImpl">
<property name="source"> <!--该name的作用是为了寻找对应的set方法,而不是属性-->
<ref bean="datasource"/>
</property>
</bean>
14、使用Spring的JdbcTemplate对象简化JDBC编程步骤
(1)修改原来的实现IUserDao接口的方法,新建一个JdbcTemplate的属性以及setSource(DataSource source)方法,核心代码如下所示:
private JdbcTemplate jdbctemplate ;
public void setSource(DataSource source) {
this.jdbctemplate = new JdbcTemplate(source); //通过Datasource对象获得JdbcTemplate对象
}
(2)修改原来的find()方法,核心代码如下所示:
List list = jdbctemplate.queryForList("select * from house_type"); //通过JdbcTemplate对象的方法获得结果集合
Iterator iterator = list.iterator();
while(iterator.hasNext()){
Map map =(Map)iterator.next();//集合中的对象都是Map类型,一个map对象包含数据库的一行记录
int i = ( (BigDecimal)map.get("id") ).intValue(); //数据如果是长整型、浮点型和整型的都需要转换
String name = (String)map.get("name");
System.out.println(i+":"+name);
}
(3)配置文件和程序入口代码不变 。
15、JdbcTemplate对象的方法介绍
(1)针对查询语句常用的方法有:List queryForList(String sql);
(2)针对DDL语句的方法是:void execute(String sql)
(3)针对插入和更新语句的方法是:int update(String sql)
(4)针对聚合函数count的方法是int queryForInt(String sql);
(5)针对带参数的Sql语句可以使用?占位符,例如:
void insert(int id,String name){
jdbctemplate.update("insert into user values(?,?)",new Object[]{id,name});
}
(6)使用batchUpdate方法进行批量操作,该方法需要两个参数
(6.1)String sql 需要执行批量操作的Sql语句,例如:insert into user values(?,?);
(6.2)BatchPreparedStatementSetter类型的参数集合,BatchPreparedStatementSetter 是一个接口,因此可以通过实现内部类的方法来得到该参数,需要实现该接口的两个方法,示例如下:
BatchPreparedStatementSetter bps = new BatchPreparedStatementSetter() {
//作用是根据下标index获得和设置参数
@Override
public void setValues(PreparedStatement ps, int index) throws SQLException {
ps.setInt(1, (Integer)Ids.get(index));
ps.setString(2, (String)names.get(index));
}
//作用是返回批量操作的次数
@Override
public int getBatchSize() {
return count;
}
};
(6.3)定义好上述两个参数就可以调用batchUpdate方法 。
17、RdbmsOperation抽象类的子类(它的子类都是线程安全的,用于针对对象进行数据库编程,类似于hibernate)
(1)SqlFunction 用于执行Sql函数,存储过程或者聚集函数的类。通过继承该类可以实现指定数据源的相关操作,步骤如下:
(1.1)新建一个类继承SqlFunction,并建立一个有参构造函数,示例如下:
public UserFunction(DataSource ds){
//可以使用?占位符来定义参数,然后需要使用setTypes方法来确定参数的类型,具体实现参考第二个方法
super(ds,"select count(*) from house_type");
compile(); //保证当前操作可以被运行
}
(1.2)利用Dao类的setDatasource方法的实例化一个UserFunction类,示例如下:
public void setSource(DataSource source) {
func = new UserFunction(source);
upd = new UserUpdate(source);
que = new UserQuery(source);
}
(1.3)调用SqlFunction的run()方法就可以执行指定的Sql语句select count(*) from house_type,示例如下:
public int countNum(){
return func.run();
}
(2)SqlUpdate
(2.1)新建一个类继承SqlUpdate,并建立一个有参构造函数,示例如下:
public UserUpdate(DataSource ds){
//可以使用?占位符来定义参数,然后需要使用setTypes方法来确定参数的类型
super(ds,"insert into house_type values(?,?)");
int[] types ={Types.INTEGER,Types.VARCHAR};
this.setTypes(types);
compile(); //保证当前操作可以被运行
}
(2.2)利用Dao类的setDatasource方法的实例化一个UserUpdate类,示例如下:
public void setSource(DataSource source) {
func = new UserFunction(source);
upd = new UserUpdate(source);
que = new UserQuery(source);
}
(2.3)调用SqlUpdate的update()方法就可以执行指定的Sql语句insert into house_type values(?,?),示例如下:
public int countNum(){
return upd.update(new Object[]{7001,"好房子没蚊子"});
}
(3)MappingSqlQuery
(3.1)新建一个类继承MappingSqlQuery,并建立一个有参构造函数,与上述两方法不同的是,该类还有一个方法需要实现,示例如下:
public UserQuery(DataSource ds){
//可以使用?占位符来定义参数,然后需要使用setTypes方法来确定参数的类型,具体实现参考第二个方法
super(ds, "select * from house_type");
compile(); //保证当前操作可以被运行
}
@Override
protected Object mapRow(ResultSet rs, int rownum) throws SQLException { //把结果集的每行记录包装成一个类并返回
HouseType type = new HouseType();
type.setId(rs.getInt("id"));
type.setName(rs.getString("name"));
return type;
}
(3.2)利用Dao类的setDatasource方法的实例化一个UserUpdate类,示例如下:
public void setSource(DataSource source) {
func = new UserFunction(source);
upd = new UserUpdate(source);
que = new UserQuery(source);
}
(3.3)调用MappingSqlQuery的execute()方法就可以执行指定的Sql语句,获得的是一个List集合,示例如下:
public List findtype(){
return que.execute();
}
最后在Spring配置文件中添加该Dao类的配置,然后就可以在主程序中获得该Dao的实例,并调用其方法获得结果。(推荐通过定义Dao接口实现上述功能)。
18、Spring和struts整合步骤(Action通过spring的Ioc注入)
(1)建立一个web工程,导入Spring和struts整合所需jar包。
(2)修改web.xml文件,添加struts和spring所需配置,如下所示:
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/applicationContext.xml</param-value> <!--该语句指向spring配置文件所在的路径-->
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
(3)添加struts的配置文件,需要在原来的配置文件内容基础上添加以下内容:
<constant name="struts.objectFactory" value="spring" /> <!--指定Action工厂使用spring-->
<action name="hello" class="userAction"> <!--class使用spring配置文件中Action的Bean的id-->
.....
</action>
(4)添加Spring的配置文件,里面需要定义一个Action的Bean
(5)Action类需要继承ActionSupport,该ActionSupport并不是Struts提供的那个,而是Spring提供的,该类所在包如下所示:
import org.springframework.web.struts.ActionSupport;
(6)完成以上步骤既可以完成Spring和struts的整合。
19、Spring和hibernate整合步骤(SessionFactory由Spring的Ioc注入)
(1)在Spring的配置文件中添加如下内容:
<!--第一个Bean是用来获得datasource的-->
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>oracle.jdbc.driver.OracleDriver</value>
</property>
<property name="url">
<value>jdbc:oracle:thin:@localhost:1521:orcl</value>
</property>
<property name="username">
<value>zzl</value>
</property>
<property name="password">
<value>zzl</value>
</property>
</bean>
<!--第二个Bean是用来获得SessionFactory的-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="datasource"/>
</property>
<property name="mappingResources"> <!--此处指定表的映射文件路径,是一个list集合-->
<list>
<value>com/pb/hibernate/entity/Grade.hib.xml</value>
</list>
</property>
</bean>
<!--通过以上两步就可以获得sessionfactory了,然后Spring就可以为dao注入,Spring和hibernate的整合主要实现的就是sessionfactory注入-->
<bean id="dao" class="com.pb.hibernate.dao.HibernateDAO">
<property name="factory">
<ref bean="sessionFactory"/>
</property>
</bean>
(2)通过上述的配置内容,我们就可以在原来的hibernate项目中修改,使得原来通过hibernate.cfg.xml配置文件获得的SessionFactory,修改为通过Spring注入。
20、Spring事务管理
(1)编程式事务管理 特点:管理的粒度比较细,可以细化到一行或几行语句,但是需要把代码陷入到业务类中,增加耦合。该事务管理方式常用的有两种方式:
(1.1)PlatformTransactionManager 接口
步骤:
(1.1.1)在Spring配置文件中添加 PlatformTransactionManager 接口的实现类 DataSourceTransactionManager的bean ,如下所示:
<bean id="TransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource"/> <!--需要使用到datasource-->
</bean>
(1.1.2)使用以下语句开启一个事务:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
------------------------------------------------------------------------------------------------------------------
PlatformTransactionManager ptm = (PlatformTransactionManager)context.getBean("TransactionManager");
DefaultTransactionDefinition dtf = new DefaultTransactionDefinition(); //实例化一个事务
dtf.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); //定义事务的行为
TransactionStatus ts = ptm.getTransaction(dtf); //开启事务
(1.1.3)把需要事务管理的业务代码放在try...catch块中,当发生异常时就使用事务管理对象(ptm)的回滚事务(ts),具体代码如下:
try{
DataSource ds = (DataSource) context.getBean("datasource");
JdbcTemplate jt = new JdbcTemplate(ds);
jt.execute("insert into house_type values(15,'一房三厅')");
jt.execute("insert into house_type values(16,'一房三厅')");
ptm.commit(ts); //用于提交操作
}catch(Exception e){
ptm.rollback(ts); //用于回滚操作
e.printStackTrace();
}
(1.2)事务模板TransactionTemplate
步骤:
(1.2.1)在Spring配置文件中添加 PlatformTransactionManager 接口的实现类 DataSourceTransactionManager的bean ,和上述第一步一样。
(1.2.2)使用TransactionTemplate封装PlatformTransactionManager接口的实现类:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
------------------------------------------------------------------------------------------------------------------
PlatformTransactionManager ptm = (PlatformTransactionManager)context.getBean("TransactionManager");
TransactionTemplate tt = new TransactionTemplate(ptm);
------------------------------------------------------------------------------------------------------------------
tt.execute(new TransactionCallbackWithoutResult() { TransactionCallbackWithoutResult的内部类
@Override
protected void doInTransactionWithoutResult(TransactionStatus arg0) {
jt.execute("insert into house_type values(17,'一房三厅')");
jt.execute("insert into house_type values(18,'一房三厅')");
}
});
(2)声明式事务管理 特点:使用Spring配置文件即可完成事务管理,但是管理只能细化到方法。耦合度低。该类事务管理也可以分成两类:
(2.1)配置代理bean实现事务管理(AOP)
步骤:
(2.1.1)在Spring配置文件中添加如下代理类配置:
<bean id="ProxyPersonDao" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="proxyInterfaces"> <!--此处指定目标类所实现的接口,代理方式都是强制依赖接口编程吗?-->
<value>com.pb.IPersonDao</value>
</property>
<property name="target" ref="persondao"/><!--此处指定目标类-->
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="transactionAttributes">
<props>
<!--此处指定该事务管理针对类的哪些方法(key),以及使用哪种行为-->
<prop key="find*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
(2.1.2)获得该接口的代理实例,并调用方法即可:
ApplicationContext context = new FileSystemXmlApplicationContext("src/applicationContext.xml");
IPersonDao dao = (IPersonDao)context.getBean("ProxyPersonDao");
/****
数据库操作....
*****/
(2.2)基于 XML Schema的声明式事务管理
步骤:
(2.2.1)由于需要使用aop和tx的标签,所以要在Spring配置文件头中添加相应的命名空间:
增加两个命名空间:
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
在xsi:schemaLocation中添加下面的语句
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
(2.2.2)该事务管理方法是需要借助spring内置的事务管理类(例如:DataSourceTransactionManager),所以需要添加相关类的配置:
<!--省略dataSource的配置-->
..........
<!--省略dataSource的配置-->
<bean id="TransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="TransactionManager">
<tx:attributes>
<tx:method name="find*" propagation="REQUIRED"/><!--指定针对的方法以及使用的事务行为-->
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="pc" expression=" execution(* com.pb.PersonDaoImpl*.f*(..))"/> <!--指定切入点-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/>
</aop:config>
(2.2.3)使用该方法不需要借助代理类,所以直接通过业务类的bean获得实例也能实现事务管理的效果。
(2.3)基于注解的事务管理
步骤:
(2.3.1)在Spring配置文件中添加以下内容:
<!--省略dataSource的配置-->
..........
<!--省略dataSource的配置-->
<!--省略TransactionManager的配置,参考上述内容-->
..........
<!--省略TransactionManager的配置-->
<tx:annotation-driven transaction-manager="TransactionManager"/><!--指定所使用的事务管理类-->
(2.3.2)在所需要事务管理的业务类中加上注解,如下所示:
@Transactional
public class PersonDaoImpl1 implements IPersonDao{
....省略部位内容.....
@Transactional(propagation=Propagation.REQUIRED)
public void find(DataSource ds){
.....省略方法中内容......
}
}
(2.3.3)完成配置。
引用:
Spring中Propagation类的事务属性详解:
1.PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
2.PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
3.PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
4.PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
5. PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
6.PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
7.PROPAGATION_NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。
21、事务属性(行为)的分类
(1)传播行为 参考spring文件夹中截图
(2)隔离级别 参考spring文件夹中截图
(3)只读提示
(4)事务超时期限
22、Spring实现计划任务
(1)通过继承TimerTask类实现计划任务,步骤如下(关键在Spring配置):
(1.1)创建一个类继承TimerTask,需要实现其中的run()方法,该方法中的内容就是需要定时执行的代码。
(1.2)配置Spring,添加如下内容:
<!--该bean就是继承了TimerTask的类-->
<bean id="update" class="com.pb.BatchUpdate">
</bean>
<!--以下是TimerTask的定义-->
<bean id="ScheduledTimerTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
<property name="delay"> <!--该参数是启动Spring后多久开始执行计划任务(单位:毫秒)-->
<value>1000</value>
</property>
<property name="period"> <!--该参数是定义任务之间延迟的时间(单位:毫秒)-->
<value>2000</value>
</property>
<property name="timerTask"> <!--该参数指定定义有定时执行方法的类-->
<ref bean="update"/>
</property>
</bean>
<!--以下是TimerTask工厂的定义-->
<bean id="timerFactory" class="org.springframework.scheduling.timer.TimerFactoryBean" >
<property name="scheduledTimerTasks">
<list>
<ref bean="ScheduledTimerTask"/>
</list>
</property>
<property name="daemon">
<value>false</value>
</property>
</bean>
(1.3)启动Spring即可实现计划任务
(2)通过MethodInvokingTimerTaskFactoryBean类的配置实现计划任务,步骤如下:
(2.1)在Spring配置文件中添加如下的内容:
<!--以下是定义了哪个类的哪个方法作为计划任务-->
<bean id="MethodInvoking"
class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean">
<property name="targetObject">
<ref bean="update"/>
</property>
<property name="targetMethod">
<value>run</value>
</property>
</bean>
<!--以下是TimerTask的定义-->
......与上基本相同.....
<property name="timerTask"> <!--该参数指定定义有定时执行方法的类-->
<ref bean="MethodInvoking"/> <!--此处修改为上述定义的MethodInvoking-->
</property>
<!--以下是TimerTask的定义-->
<!--以下是TimerTask工厂的定义-->
....与上同.....
<!--以下是TimerTask工厂的定义-->
(2.2)包含计划任务方法的类不需要继承TimerTask 。直接启动Spring即可。
(3)使用Quartz实现计划任务,分为传统型和精确型两类(注意:必须导入quartz-all-1.6.0.jar和jta.jar)
(3.1)传统型,实现步骤如下:
(3.1.1)创建一个类继承QuartzJobBean类,并重写void executeInternal(JobExecutionContext arg0)方法,里面的内容就是计划任务需要执行的代码。
(3.1.2)在Spring配置文件中添加如下内容:
<!--以下是任务类的配置-->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass">
<value>com.pb.BatchUpdate</value> <!--引用的类全限定名,注意不需要另外定义计划任务类的bean-->
</property>
<property name="jobDataAsMap"> <!--类中所包含的属性需要注入的值-->
<map>
<entry key="command">
<value>更新</value>
</entry>
</map>
</property>
</bean>
<!--以下是触发器的配置-->
<bean id="SimpleTriggerBean" class="org.springframework.scheduling.quartz.SimpleTriggerBean" >
<property name="jobDetail"> <!--指定使用的任务类-->
<ref bean="jobDetail"/>
</property>
<property name="startDelay"> <!--指定开启Spring后多少时间执行计划(单位:毫秒)-->
<value>1000</value>
</property>
<property name="repeatInterval"> <!--指定任务之间的重复执行时间间隔(单位:毫秒)-->
<value>2000</value>
</property>
</bean>
<!--任务工厂配置-->
<bean id="beanFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="SimpleTriggerBean"/>
</list>
</property>
</bean>
(3.1.3)完成配置,启动Spring即可。
(3.2)精确型,实现步骤如下:
(3.2.1)与3.1.1的内容相同
(3.2.2)和3.1.2内容基本相同,但是关于触发器的配置修改为如下所示:
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail"> <!--指定使用的任务类-->
<ref bean="jobDetail"/>
</property>
<property name="cronExpression"> <!--指定执行的时间,例如:每天的01:40:00-->
<value>00 40 01 * * ? </value>
</property>
</bean>
(3.2.3)完成配置,启动Spring即可。
(3.3)使用模板实现quartz
步骤如下:
(3.3.1)不需要继承任何类,只需要定义一个普通的类即可,其中包含计划任务执行的方法。
(3.3.2)在Spring配置文件中添加如下语句:
<!--配置任务类-->
<bean id="update" class="com.pb.BatchUpdate">
<property name="command">
<value>插入</value>
</property>
</bean>
<!--配置MethodInvokingJobDetailFactoryBean,用于指定计划任务调用的类以及方法-->
<bean id="MethodInvoking"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<ref bean="update"/>
</property>
<property name="targetMethod">
<value>executeInternal</value>
</property>
</bean>
-----------------------------------------------------------------------------------------------
<!--以下是触发器的配置-->
....内容基本和前面方法一样...
注意以下内容:
<property name="jobDetail"> <!--指定使用的任务类-->
<ref bean="MethodInvoking"/> <!--这里使用上述定义的MethodInvokingJobDetailFactoryBean的id-->
</property>
<!--以下是触发器的配置-->
<!--任务工厂配置-->
....内容基本和前面方法一样...
<!--任务工厂配置-->
(3.3.3)完成配置,启动Spring即可。
Spring 技术总结相关推荐
- 社群:加入 Spring 技术学习群
入群须知 为了构建高质量的技术交流社群 减少低质量内容的产出,建议入群前先阅读本须知 了解本社群所涉及的内容主题与相关群规 社群主题:Spring技术 适合人群: 已经具备Java基础能力(若还没有J ...
- 华章揭秘系列精品图书(《Android应用开发揭秘》、《GWT揭秘》、《Spring技术内幕》)...
Android应用开发揭秘(国内首本基于Andriod 2.0的经典著作,5大专业社区一致鼎力推荐!互动网畅销排行榜第1名) 作者:杨丰盛 出版社:机械工业出版社 标准书号:978-7-111-291 ...
- 《Spring技术内幕(第2版)》PDF 国内经典分析spring源代码
书名:Spring技术内幕(第2版) 作者: 计文柯 出版社: 机械工业出版社 副标题: 深入解析Spring架构与设计原理 出版年: 2012-2 页数: 399 定价: 69.00元 装帧: 平装 ...
- java布道师_我和 Spring 技术布道师的一天
摘要: 先介绍一下故事的5位主人公. Josh Long 龙之春:Spring 技术布道师,撰写过5部著作,录制过3部畅销的培训视频,是一位开源软件贡献者. Spencer Gibb:Spring 技 ...
- 资深架构师推荐Spring技术内幕:深入了解Spring的底层机制
程序员都很崇拜技术大神,很大一部分是因为他们发现和解决问题的能力,特别是线上出现紧急问题时,总是能够快速定位和解决. 一方面,他们有深厚的技术基础,对应用的技术知其所以然,另一方面,在采坑的过程中不断 ...
- Spring技术内幕
Spring技术内幕--深入解析Spring架构与设计原理 图 书 内 容 本书是Spring领域的问鼎之作,由业界拥有10余年开发经验的资深Java专家亲自执笔!Java开发者社区和Spring开发 ...
- Spring技术内幕:设计理念和整体架构概述
为什么80%的码农都做不了架构师?>>> 程序员都很崇拜技术大神,很大一部分是因为他们发现和解决问题的能力,特别是线上出现紧急问题时,总是能够快速定位和解决. 一方面,他们有深 ...
- spring技术的通俗理解
spring技术内容太过庞杂,笔者尚在学习之中,以下理解难免有错漏之处,还请大神们提点. 一提到spring技术,随之而来的必然就是这样3个名词:控制反转IOC,依赖注入DI.面向切面编程AOP.但是 ...
- Spring技术内幕总结
最近一段时间看了一下书名叫<Spring技术内幕--深入解析Spring架构与设计原理>,这么熟将spring写的非常的经典,将spring所有的内幕技术解析的非常的详细,自己只是粗略的大 ...
- 一次Spring技术的面试,被面试官怼的怀疑人生。。
Spring无论在Java生态系统,还是在就业市场,是绝对的王者.面试出镜率之高,投产规模之广,无出其右.随着技术的发展,Spring 从往日的 IoC 框架,已发展成 Cloud Native 基础 ...
最新文章
- 这套“人造肌腱”装备,可保护你的老腰|Science子刊
- python与excel结合-python3与Excel的完美结合
- 【转】eclipse android 设置及修改生成apk的签名文件 -- custom debug keystore
- Ribbon源码解析(一)
- ubuntu xfce下面两个终端合并为一个终端
- python bool值要注意的一些地方
- IT 人永远不老,老程序员价值何在?
- SQL Server 锁升级阈值
- 表格中复制后出现空格_软件应用在Excel表格中怎样批量删除空格?
- Linux综合练习——课件分发
- Nginx之rewrite配置
- 2019年,有远见的程序员都在关注这些硬核公众号
- Oracle10g安装在RHEL AS 3
- Java使用HttpURLConnection上传文件
- 2016-7-3 linux学习笔记
- 成功自我暗示三大规律
- 谷歌“Adobe Flash Player已被屏蔽”的解决办法
- mysql sniffer下载_Gitee 极速下载
- linux系统忘记密码之破解密码
- antd mobile在微信公众号开发中使用笔记
热门文章
- JS正则匹配所有中文字符
- 电脑远程控制,win7远程控制电脑_Win7系统怎么远程控制别人的电脑
- linux创建、删除、编辑、文件,目录,权限等
- python提取邮件里面的发件人
- 项目一 51单片机蓝牙控制继电器
- 基于C++实现(MFC界面)家谱管理系统【100010005】
- 手机登录群晖出现ssl证书不可信_教你申请免费SSL证书以及安全访问群晖的方法教程...
- 利用VBA快速整合多个excel文件
- SpringBoot从入门到精通教程(二十七)- @Valid注解用法详解+全局处理器Exception优雅处理参数验证用法
- 怎么使用gulp压缩文件、图片