文章目录
Spring
引言
- 软件的生命周期
开始: 开发完毕,初次使用。
结束: 软件升级和维护,代价非常大,大到不如重新开发。
- 现有代码的问题
获得对象: 在使用对象的位置,直接使用new的创建对象
缺点: 通过new的直接获得对象 ,存在耦合。
- 工厂设计模式
思想:
- 工厂对象 BeanFactory:获得对象,创建对象。
- 获得对象: 从工厂对象中,获得需要的对象。
- 总结工厂设计模式[重点]
核心思想
使用步骤:
-
将类信息注册在工厂的配置文件中。
-
编码:创建BeanFactory工厂。
-
编码:调用getBean方法,获得需要的对象。
factory.getBean("要获得对象类名对应key")
Spring简介
简介: Spring是一个轻量级企业开发框架,核心: IOC编程,AOP编程。
IOC:[重要]
I(Inverse) O(Of) C(Controll)
控制反转
概念: 将对象创建的权利,转义到(Spring)工厂中。
目的: 将对象创建的耦合,解耦和。
Spring工厂
核心编程思想:
Spring工厂:
BeanFactory(接口):
ApplicationContext(接口):
//本地使用Spring工厂实现类:
ClassPathXmlApplicationContext(实现类);----在本地环境下使用(主函数启动)
XmlWebApplication(实现类); ---在web环境下使用。(从tomcat环境启动)
Spring配置文件:
applicationContext.xml
beans.xml
Spring环境搭建
-
导入需要的jar
导入spring的jar
导入spring依赖的commons-loggin的jar
-
导入配置文件。
导入
aopplicationContext.xml
配置文件,src的任意目录下即可。导入
log4j.properties
配置文件,src的根目录下。
Spring工厂的使用步骤
核心思想
工厂步骤
1. 将类名信息注册在applicationContext.xml
① bean标签的class:类名信息
② bean标签的id:对应的名字 getBean(name)
<bean class="全类名" id="获得该对象使用name">
2. 编码:创建spring工厂
ApplicationContext factory = new ClassPathXmlApplicationContext(配置文件路径);
3. 编码:调用factory的getBean方法获得对象。
factory.getBean("bean标签的id");
控制对象创建的次数
1. 默认spring工厂创建对象的次数 1个。(创建单个,单实例)
应用: SqlSessionFactory HttpServlet DataSource(连接池) XxxService
2. 创建多个
bean scope="prototype"
示例:
<bean
id="us"
class="com.baizhi.demo1.UserServiceNewImpl"
scope="prototype">
</bean>
应用: Action控制器(Controller) SqlSession Connection
Spring工厂属性注入(属性赋值)
IOC DI思想
概念:
IOC Inverse Of Controll 反转控制(控制反转):
将对象创建的权利,从当前代码转移到spring工厂完成。
DI Dependency Injection 依赖注入
依赖: 对象的属性 依赖注入:给对象的属性赋值
总结[重点]
IOC/DI 反转控制 依赖注入 1. 将对象创建的权利转移到spring工厂中。 2. 将对象的属性赋值的权利,转移到了spring工厂中。
依赖注入的编码
-
String+基本数据类+包装类型
核心思路:
1. 将对象交给spring工厂管理 <bean id="" class=""></bean> 2. 属性赋值--依赖注入 ① 属性必须提供标准的get和set方法。 ② 在配置文件完成。 <bean id="" class=""> <property name="要赋值的属性名" value="值"></property> </bean> 补充: String+基本数据类型包装类值表示 <property value="string或者int类型的值"></property> <property> <value>string或者int类型的值</value> </property>
2. List和数组类型
<property name="list属性名">
<!--list类型值-->
<list>
<!--每个值: string 基本数据类型 包装类型-->
<value>值1</value>
<value>值2</value>
<value>值3</value>
<value>值4</value>
</list>
</property>
3. Map
<property name="属性名">
<!--map类型的值-->
<map>
<!--map中每个元素包含key+value(entry)-->
<entry key="key" value="value"></entry>
<entry key="key1" value="value1"></entry>
<entry key="key2" value="value2"></entry>
</map>
</property>
-
Properties
1. Properties类型数据结构(key value) 2. 使用spring工厂创建propertie啥类型的值,并给属性赋值 <property name="属性名"> <props> <prop key="k1">值value1</prop> <prop key="k2">值value2</prop> </props> </property>
-
用户自定义类型
赋值原理
spring配置文件属性或者标签的底层原理
1. bean标签 class属性
<bean id="user" class="com.baizhi.demo2.User">
底层:
String classstr = "com.baizhi.demo2.User";
Class clazz = Class.forName(classstr);
Object o = clazz.newInstance();
2. property标签 name属性 值
作用: 给属性赋值。
底层:
调用的是property标签的name属性名对应的set方法【属性名首字母大写,前面添加set】
总结:property标签的赋值原理是set方法。
使用有参构造方法给属性注入
1. 使用有参构造方法给属性赋值
<bean id="" class="">
<!--使用有参构造方法给属性赋值
index: 参数位置,序号
value: 给的实际的参数。
-->
<constructor-arg index='参数序号,从0开始' value="101"></constructor-arg>
<constructor-arg index='参数序号,从0开始' value="101"></constructor-arg>
</bean>
特殊对象的创建
比如:
Connection
SqlSession
DataSource
SqlSessionFactory
//创建connection 1. 加载驱动 Class.forName("oracle.jdbc.OracleDriver"); 2. 获得conn Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe","hr","hr");
核心编码思路
思路:
- spring允许用户自己通过编写代码(实现FactoryBean接口),提供获得对象的方式。
- spring获得对象,可以借助于FactoryBean的getObjec方法获得对象。
编码步骤:
-
自定义类,告知spring如何获得对象。
public class ConnectionFactory implements FactoryBean<Connection>{ //spring获调用getObject方法,间接获得conn并管理在spring工厂中。 public Object getObject(){ //获得复杂对象的代码。 } //该方法告知spring对象管理个数 。 //return true;一个 //return false;//多个。 public boolean isSingleton(){ return false; } }
-
将FactoryBean接口的实现类交给spring工厂管理.
<bean id="connFactory" class="xxx.xxx.xxx.ConnectionFactory"></bean> 补充: 如果class对应的全类名实现FactoryBean接口 ① bean标签作用就自动调用该类的getObject方法,获得对象,并将对象管理起来。 ② 该被管理起来的对象的id "connFactory"
-
从spring工厂获得该connection对象
factory.getBean("connFactory"); 作用: 获得 connFactory对应的bean标签的class对应的类的getObject方法的返回值。
总结
-
SpringIOC /DI思想
思想:反转控制,依赖注入,将对象创建的权利,从当前的代码中转移spring工厂中,对象属性赋值的权利转移到spring工厂中。
编码:
applicationContext.xml 1. <bean></bean> 创建对象,并且将对象管理在spring工厂中. 2. <property></property> 通过set方法给属性进行赋值。(依赖注入) 3. <constructor-arg index="" value=""></constructor-arg> 通过有参构造方法给属性赋值。
作用: 将代码的对象与对象之间的耦合,解耦和操作。
应用:
DAO Service Controller/Action DataSource(连接池) SqlSessionFactory(mybatis创建sqlsession)
图:
2. IOC和DI的配置文件和编码
- 掌握特殊对象创建。
Spring AOP
引言
现有代码的问题:
- 事务代码耦合: 现有的事务控制的代码,耦合在了service方法中,一旦数据库访问技术发生变化,所有事务控制代码需要替换,导致service的代码被大量的修改!
事务控制的代码冗余: 大量相同的事务控制代码出现在了service方法中,出现冗余代码,不利于后期的升级和维护!
解决思路:
通过手动添加代理类,将事务控制代码放在代理类中。
代理类的核心规范 · 静态代理[重点]
- 先和目标类实现相同的接口
- 将额外功能(事务控制),放在代理类中。
- 调用目标对象的目标方法。
作用: 将事务代码和service的核心功能代码解耦和。
总结 代理类核心要素
- 和目标类相同的接口
- 额外功能
- 调用目标对象的方法。
- 代替目标对象接受调用.
静态代理的缺点
每个目标类都要书写一个代理类,存在代码冗余
Spring AOP·动态代理
动态代理: 使用技术动态为目标类生成代理类。
SpringAOP技术实现步骤
代理类核心
- 额外功能。
- 调用目标对象的方法
- 和目标类拥有相同的接口。
Springaop技术的核心思想
- 将额外功能的代码放在功能增强的对象中。
- springaop技术,将功能增强中的额外功能的代码,动态生成代理类,添加进去。
springaop的步骤
- 导入springaop依赖的jar。
asm
cglib
aspectj.awear
-
准备目标类,将目标类的对象交给spring管理。
-
书写额外功能所在的 功能增强类。
public class 增强类 implements org.aopalliance.intercept.MethodInterceptor{ /** * 额外功能: * 调用目标对象方法。 */ @Override public Object invoke(MethodInvocation mi) throws Throwable { //1. 开启事务 System.out.println("开启事务"); //2. 调用目标对象的功能。 Object o = mi.proceed();//调用真正的目标对象的方法。 //3. 提交事务 System.out.println("提交事务"); return o; } }
-
通过aop技术,动态生成代理类=额外功能+目标对象
核心
① 额外功能加入的位置: 切入点
告诉spring将额外功能代码放在哪个方法的内部[告诉spring将额外功能加入哪个类的哪个方法中。]
② 组装: 额外功能+类、方法(切入点)==代理类。
SpringAOP编程思想
看起来
思想: AOP aspect orinted programing 面向切面编程。
在不修改目标的代码的情况下,动态的为目标类的方法添加额外的功能代码。
本质:
使用jdk技术,动态为目标类生成了代理类的,生成代理的对象,使用生成的代理对象替换了你的原始的目标对象。
民间解释: 偷梁换柱 偷天换日 李代桃僵 借尸还魂 狸猫换太子
MethodInterceptor详解
// 增强功能对象: 通知 建议。
public class XxxAdvice implements MethodInterceptor{
/**
* 额外功能:
* 调用目标对象方法。
*/
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
//mi: 代表目标对象的方法。
Object o = mi.proceed();//调用目标对象的目标方法。
return o;
}
}
1. 获得目标对象的方法
mi.getMethod();//Method 类型的目标方法。
2. 目标对象
mi.getThis();//获得目标对象
3. 获得代理的目标方法的调用时,实际传入的参数
mi.getArguments();//数组,实际传入的参数。
4. 调用目标对象的目标方法
Object o = mi.proceed();//us.regist() ps.add()
//① 调用目标对象的方法
//② 返回值代表实际被代理的方法的返回值。
切入点表达式详解
pointcut切入点: 告诉spring功能增强的目标类的目标方法
execution
语法: expression=“execution(切入点表达式)”
特点: 精确到方法声明的。
1. 精确点指定包指定类指定方法。
execution(返回值 包名.子包.孙子包.类.方法名(参数1类型 参数2类型));
2. 精确到指定包下的指定类的执行方法,参数任意:
execution(返回值 包名.子包.孙子包.类.方法名(..));
3. 精确到指定包的指定类,方法名任意,参数类型任意
execution(返回值 包名.子包.孙子包.类.*(..));
4. 精确指定包下的任意类,任意方法,任意参数类型。
execution(返回值 包名.子包.孙子包.*.*(..));
5. 精确到指定包下的类,及其子包下的所有类的任意方法,任意参数
execution(* p1.p2.p3..*.*(..));
//将p1包下的p2包下的p3包下的所有类,及其子包下的所有类,任意方法,任意参数,任意返回值类型
within
语法: expression=“within(表达式语法)”
特点: 表达式的写法,只精确到类。
示例:
within(包名.类名)
给指定包及其子包下的所有类。 within(p1.p2.p3..*);
@annotation
语法: expression="@annotation(注解全类名)"
特点: 凡是添加指定注解的方法,都会被功能增强。
使用步骤:
1. 定义注解。 public @interface HeheAdvice{} //给定含义: 添加了HeheAdvice注解的方法,都会被功能增强。 2. 使用注解: 给需要功能增强的方法添加注解 public class AServiceImpl{ @HeheAdvice //希望给a1方法做功能增强。 public void a1(){} } 3. 通过切入点,指定:添加@HeheAdvice的方法,进行功能增强。
技术补充:
日志
记录代码运行中所有涉及到相关信息。
作用:
- 便于调错。
- 监控系统运行情况。
记录信息:
类 方法 参数 什么时间
如何使用日志:
1. 导入jar:commons-loggin.jar 2. 在需要使用日志位置: 获得日志工具: Log log = LogFactory.getLog(所在的当前类的类对象); 调用日志工具打印方法: log.info("日志信息");
重点:
-
aop思想和本质
思想(表面)
在不修改目标类的代码情况下,动态为其添加额外功能代码,在目标方法之前运行一段代码,目标方法结束执行一段代码(位置: 目标方法一开始,目标方法最后)
SpringAOP技术(本质):
使用java技术,动态为目标类,生成代理类,生成代理类的对象,将代理对象替换原有的目标对象。
调用者在使用目标对象,被代理对象替换了【借尸还魂 李代桃僵】
符合aop编程思想的技术:
SpringAOP技术
过滤器
Struts2的拦截器
2. Springaop编码步骤(目标对象 曾强功能 切入点+组装)
1. 准备好目标类,且将目标对象交由spring管理: <bean> 2. 书写增强功能类,交给spring管理。[Advice 增强 切面 通知 建议] 3. 使用springaop技术[标签],组装生成代理类的对象,替换目标对象。 <aop:config> 声明切入点: <aop:pointcut id="pc" expression="execution(精确到方法)|within(精确类)|@annotation(指定添加的了注解全类名)"> 组装: 代理类=切入点+增强, 生成代理对象 将代理对象替换目标对象 <aop:advisor pointcut-ref="pc" advice-ref="增强切面id"></aop:advisor> </aop:config>
-
切入点表达式:execution和@annotation语法
execution(返回值 包名.类名.方法名(参数类型1 参数类型2))
应用场景
核心思想:
抽取java代码中通用功能(冗余代码,重复代码),使用aop技术。
>
应用场景:
- 事务控制。
- 日志打印。
- 性能监控。
- 权限(登录验证)–使用Filter 或者 拦截器
补充:功能增强的位置:
JdbcTemplate
Spring简化JDBC
谁: Spring提供的。(spring-jdbc.jar)
作用: 简化JDBC的代码。
常用API
-
如何获得JdbcTemplate
1. 交给spring管理
导入相关的jar:
spring的jar
数据库驱动jar
阿里的连接池的jar
2. 如何从spring工厂获得JdbcTemplate
- 增删改方法
jdbcTemplate.update(sql,参数列表...)//执行增删改操作。
- 查询方法(查询单个)
T t = jdbcTemplate.queryForObject(sql,映射工具RowMapper接口,绑定参数);
//RowMapper:在这个对象中maprow方法,手动完成rs和实体映射关系。
//返回值:就是查询结果。
注意:查询没有结果,异常形式告知。
- 查询多条结果
List<T> list = jdbcTemplate.query(sql,RowMapper,绑定的参数);
//查询结果是多条数据。
Spring+JdbcTemplate开发应用
DAO层+Service层
编码步骤
-
表
-
实体
-
书写DAO
实现类
-
开发Service
实现类
Spring工厂的管理规范
-
需要spring管理的对象
XxxxService XxxDAO JdbcTemplate dataSource连接池
-
Spring容器内部对象管理
- 补充:
Spring管理对象: 功能性: JdbcTemplate 连接池 DAO Service Action 不会使用spring管理: 数据型对象: 实体 XxxQuery对象
Spring声明式事务
思路:
将UserService作为目标类,管理在spring工厂。
配置管理spring提供,事务管理器。
封装了事务控制的方法。
使用spring工厂管理事务增强(spring内置事务增强)。
使用aop技术,为目标对象添加事务.
操作步骤:
- 管理service的目标类。
spring管理事务管理器。
spring管理事务增强 tx:adivce 替代了 bean
- aop配置将增强加入service方法中
事务属性
事务属性配置标签和属性
<tx:attributes> <tx:method name="方法名1" read-only="只读" propagation="事务传播" rollback-for="回滚异常"></tx:method> <tx:method name="方法名2" ></tx:method> <tx:method name="方法名3" ></tx:method> </tx:attributes>
-
事务回滚
rollback-for: 指定service的方法,在什么异常情况下进行事务回滚操作。
<tx:method name="regist" rollback-for="java.lang.RuntimeException"></tx:method> 默认: rollback-for默认值 java.lang.RuntimeException
-
只读事务
read-only: 只读。
作用: 可以让serviec的查询方法在数据库的内存中,事务中,不分配回滚段。节省内存。
应用: service方法只有读操作,建议设置为只读:
read-only="true"
-
事务传播
问题:service调用service
propagation=“SUPOORTS|REQUIRED”
SUPPORTS: 支持事务。
特点:
① 如果外部已经开始了事务,并融合到外部事务中。
② 如果外部没有开启事务,则不开启事务。
REQUIRED: 需要事务
特点:
必须要有一个事务。
① 如果外部已经开启事务,则融合外部事务中。
② 如果外部没有事务,则开启事务。
应用
1. 查询方法: 外部有事务,则融合,外部没有事务,没必要开启。 SUPPORTS 2. 添加,删除,修改业务方法: 外部已经开启事务,则融合。如果外部没有事务,则开启事务。REQUIRED
-
事务属性方法的简化
<tx:method name="get*" propagation="SUPPORTS" read-only="true"/> 含义: 只要service方法以get开头,都适用于,只读,支持事务这些设置。
Spring整合Struts2
问1: 将struts2的action交给spring管理。
核心思想:
ng)
问题2:spring工厂需要在Tomcat启动的时候就初始化完毕?
解决问题:
- ServletContextListener监听器的代码,可以在tomcat启动时执行的。
- 就spring工厂初始化的代码,放在ServletContextListener。
注: Spring内置ServletContextLisnter监听器,用来在tomcat启动的时候初始化spring工厂
org.springframework.web.context.ContextLoaderListener
开发步骤
环境搭建
-
导入相关的jar
spring的相关jar struts2的相关的jar struts2-spring-plugins的jar commmons-logging日志jar
-
导入配置文件
1. spring的配置文件【放在src下任意目录】 applicationContext.xml 2. log4j日志文件【必须放在src根目录下】 3. struts2的配置文件 struts.xml【必须放在src根目录下】 4. web.xml配置文件。
-
初始化配置
<!-- 1. struts2的核心控制器 --> <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> <!--2. 初始化spring工厂的监听器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!--3. 手动指定配置文件路径 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:/applicationContext.xml</param-value> </context-param>
开发Sturts2action
-
action开发
-
交给spring管理 创建多个
-
配置action的访问路径。
SSJ整合
Spring+Struts2+JdbcTemplate
搭建环境
1. 导入相关的资源(jar+配置文件)
相关的jar
spring相关
struts2相关
ojdbc5.jar
druid连接池的jar
struts整合spring的jar
日志的jar
aop依赖的jar
asm-3.3.1.jar
cglib-2.2.2.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
相关的配置文件
applicationContext.xml
struts.xml
log4j.properties
web.xml
2. 初始化配置
环境搭建类型的初始化
struts核心控制器
spring工厂初始化监听器
指定spring配置文件路径。
编码相关的初始化
初始化spring配置文件中常用的内容
连接池
JdbcTemplate
txManager
tx:advice
aop:config
Spring工厂内部:
编写代码
注册功能: 1. 表 2. 实体 3. DAO 和实现类 交给spring管asdf理。 4. Service和实现类,交给spring管理 5. Action,交给spring管理,scope="prototype" struts.xml注册action访问信息,跳转路径信息。 <action name="" method="" class="action在spring工厂中的id">
Spring整合MyBatis
核心思想
环境搭建
-
导入jar
1. spring jar 2. mybatis jar 3. aop 的jar 4. ojdbc5.jar 5. 连接池的jar 6. 日志的jar 7. mybatis-spring的jar。 提供两个核心类: SqlSessionFactoryBean 替代mybatis-config MapperScannerConfigurer 代替mybatis生成dao对象的代码。 注意: 生成dao的id是对应接口的首字母小写。
-
导入配置文件
1. applicationContext.xml 2. log4.properties
-
初始化配置
开发步骤
需求:书写DAO完成添加user的功能?
1. 表 2. 实体 3. DAO接口 4. DAO接口对应的Mapper文件。 5. 获得dao,调用方法测试
SSM整合
搭建环境
1. 导入jar
spring mybatis struts2 mybatis整合spring struts整合spring aop 连接池 日志 ojdbc5.jar
2. 导入配置文件。
struts.xml
spring.xml
log4j
web.xml
3. 初始化配置
web.xml配置
① struts2核心控制器
② spring工厂初始化的监听器
③ spring配置文件路径
applicationContext.xml
① 连接池
② 事务相关配置【txManager tx:advice aop】
③ 初始化mybatis整合相关配置
sqlSessionFactory
生成dao对象
开发步骤
注册user功能
1. 表 2. 实体 3. dao接口 4. Mappe文件 spring自动管理dao对象。 5. Service接口 6. service实现类 Spring管理service对象 7. Action类 spring管理action 【创建多利】 映射action的访问路径和跳转路径 【class="action在spring工厂中的id"】
Spring注解
开启spring注解:
applicationContext.xml <context:component-scan base-package="com.baizhi"></context:component-scan> 作用: Spring会扫描com.baizhi包下的类及其子包下的所有类,启动注解。
SpringIOC注解
有spring工厂创建对象,并管理对象
@Component 使用:在要交给spring工厂管理的类上。 语法: @Component("对象在spring工厂中的id") public class Xxxx{ } 作用: 1. 创建当前对象。 2. 交给spring工厂管理起来了。
2. 不指定对象的id@Component public class UserServiceImpl implements UserService{} 注意:当前对象在spring工厂中的id="userServiceImpl"
- spring管理多利对象
@Scope(“prototype”) 当前对象在spring工厂每次创建一个新的对象
@Component("userAction") @Scope("prototype") public class UserAction { private UserService userService; }
通常,只有程序员写的类,才能使用注解交给spring管理。
专门给三层结构类使用的**@Component**子注解
目的: 使用注解管理拥有分类语义。 特点: 和@Component功能和使用完全一致。 @Controller 控制器类 @Service 业务类 @Repository dao类使用
SpringDI注解
@Autowired
使用: 添加在属性上,需要通过spring工厂注入的属性。 作用: spring工厂会从工厂内,1. 查找符合该属性类型的对象, 2. 自动查找到的对象,赋值给该属性。 注意: 注解@Autowired注入的属性,可以省略属性的get和set方法。
@Qualifier1. 使用: 配合@Autowired使用。 2. 含义: 在spring工厂查找符合属性类型的对象,当注入给属性时,限定要注入对象的id。
Spring注解整合Junit测试
使用步骤:
- 导入spring-test的jar和junit的jar。
spring-test.jar junit.jar hamcrest.jar
整合Spring和Junit
测试注解加载spring工厂。
@RunWith(SpringJunit4ClassRunner.class)//整合spring+Junit @ContextConfiguration("classpath:配置文件路径")//初始化spring工厂,并且指定配置文件路径。 public class 测试类{ @Test public void test1(){ //指定测试的代码。 } }
SSM整合注解版本
搭建环境
1. 导入相关的jar
2. 导入相关的配置文件。
3. 初始化SSM开发环境初始化配置
web.xml
struts2核心控制器
spring工厂监听器
spring配置文件
applicationContext.xml
开启spring注解
context:component-scan base-package="包1.包2.包3"
连接池
事务相关内容[txManager txadvice aop]
mybatis整合相关: sqlSessionFactoryBean MapperScannerConfigurer
编码
注册功能:
1. 表
2. 实体
3. DAO接口,Mapper文件。
4. Service接口,Service实现。 交给spring工厂管理[@Service注解]
5. Action,交给spring工厂管理[@Controller注解 @Scope("prototype")]
6. 映射action的访问路径 struts.xml
<action name="" method="" class="spring工厂中的action的id">
补充
spring集成properties配置文件。
spring引入外部properties配置文件。
<context:property-placeholder location="外部properties配置文件的路径"></context:property-placeholder>
获得properties中的值
坑:
1. properties配置文件中的key不要使用“username” 2. 命名规范: 前缀.name=value applicationContext.xml ${前缀.name} 3. spring配置文件中 MapperScannerConfigurer中无法是使用properties配置文件中的值。 原因: 加载时间早于properties配置文件的加载。
aop增强类型[通知类型]
MethodInterceptor 书写增强代码 环绕增强 环绕通知
特点:前置增强, 后置增强,异常位置增强。
MethodBeforeAdvice
解释:
前置增强. 使用: public class XxxAdvice implements MethodBeforeAdvice{ public void xxx(...){ //代码。 } }
AfterReturningAdvice
后置增强
>
ThrowsAdvice 异常通知。
Spring面试专题[重点]
面试技巧(3个)
案例1:
技巧1: 从实际应用的角度,把技术的本质解释说来。(绝对不能只说概念) 1. int和Integer的区别? int基本数据类型,默认值是0。 Integer包装类型,对象类型,默认值是null。 Integer可以表示null,int无法表示null,比如在做学生考试系统信息:成绩信息Integer类型(null可以表示缺考,0表示考试了0分) 2. ==和equals区别? ==:比较的变量内存储的数据: 基本数据类型: a == b; 比较的是字面值。 对象类型: Person p1 = ...; Person p2 = ...; p1 == p2;比较的对象的地址。 equals: p1.equals(p2); 方法: 默认继承Object类的equals方法,比较地址。 通过本类覆盖equals方法,实现比较内容的效果。
案例2:
技巧2: · 回答技巧: 举例子,怎么用的,就怎么说!(从实际应用角度解释) 1. 说一下你对springaop的理解? 官方: AOP编程思想的实现,面向切面编程,从思想(表面),在不修改目标代码情况下,动态为其增加额外功能代码。 SpringAOP本质:通过java技术,动态为目标类生成代理类,并且产生代理对象,替换目标对象接受调用。 回答技巧: 举例子,怎么用的,就怎么说!(从实际应用角度解释) 面向切面编程,比如,我在做xxx项目的时候,xx功能(事务,日志,性能监控),可以在一开始不关注任何事务和日志的和性能的代码,直接写service的核心业务功能,可以通过springaop技术动态为service增加上事务,日志,性能监控,不会对原有代码产生任何修改。(示例,别背);
案例3:
技巧:如果知道技术的原因,底层原理,尽量多描述. 1. String和StringBuild的区别? String不可变 不可变: "abc" "abcd" ① 为什么String是不可变的?(怎么实现不可变) final修饰,导致String不能被继承,不能通过子类的方法替换String的实现. String内部是使用char[]实现,且没有提供任何修改字符串内容的方法。 ② 为什么String要设计成不可变的? String有特性 串池: 特点: 串池中共享字符串对象,重复使用。 作用: 节省字符串对象重复创建消耗的时间和内存空间。(提高字符串使用效率,性能,优点) 避免串池在共享字符串出现线程不安全的问题. 缺点: 字符串拼接。 "a"+"b"+"c"+"d" 产生大量的中间对象,无用对象浪费创建时间,浪费了内存空间。(效率低) StringBuilder可变 优点: 可变字符串。 字符串拼接,可以直接在StringBuilder对象上修改。效率高。 2. springaop技术的理解? 面向切面编程, 比如。。。。。。。 原理: .... 警告: 如果不理解,别背,也别说。
SpringIOC/DI原理
SpringIOC /DI 思想: 反转控制,依赖注入,将对象创建的权利,从当前的代码中转移spring工厂中,对象属性赋值的权利转移到spring工厂中。 原理: 工厂设计模式+反射+配置文件 工厂设计模式: public class BeanFactory{ public Object getObject(String name){ //根据name获得对应的全类名(properties配置文件) String name = ...; Class clazz = Class.forName(name); return clazz.newInstance(); } } 应用好处(使用): 解耦和 将对象创建和属性赋值的耦合解开。 比如开发中Service,Controller,DAO对象,连接池,事务管理器,都可以从spring工厂中获得,实现了解耦和效果。
详解:
SpringAOP底层实现原理
AOP思想: 面向切面编程,在不修改目标代码的情况的情况下,动态为其增加额外功能。 SpringAOP技术: 本质:使用了动态代理的设计模式,为目标类的代码,生成一个代理类,产生代理对象,替换目标对象接受调用。
静态代理
1. 编码
目标对象相同的接口。
额外功能
拥有目标对象,调用目标对象的方法
2. 代码:
public class UserServiceProxy implements UserService{
private UserService userService = new UserServiceImpl();
public void regist(){
System.out.println("前置增强");
//调用目标对象的方法
userService.regist();
System.out.println("前置增强");
}
}
3. 解释
作用: 实现了事务,日志,权限,性能代码解耦和。
缺点: 所有静态代理类,都是程序员人工编写,为每个目标类,都要书写一个代理类,代码冗余。
Jdk动态代理[基于接口的]
动态代理:
代理类是通过代码自动生成的。
特点:
要求目标类必须有接口。
//直接生成代。
Object proxy = Proxy.newProxyInstance(ClassLoader,目标类的接口,增强功能类);
//重要参数:
ClassLoader: 动态字节码技术,动态生成一个类信息的byte[],借助于classloader,将byte[]转化为Class对象。
目标类接口:UserService
public class Proxy0 implements UserService{
public void regist(){
//
}
}
增强功能类: 书写额外功能,类似Spring的MethodInterceptor。
代理类产生过程
类加载
ClassLoader拥有将存储类信息的字节数组,转化为Class对象
JDK动态代理的代码实现
1. 目标对象
UserServiceImpl
2. 额外功能增强的类
InvocationHandler
3. 生成代理类
Object proxy = Proxy.newProxyInstance(类加载器,目标类的接口,增强功能);
public static void main(String[] args) {
//1. 准备目标对象
final UserService us = new UserServiceImpl();
//2。 准备额外功能
InvocationHandler handler = new InvocationHandler() {
/**
* proxy: 产生当前代理对象
* method: 目标对象的方法
* args: 目标对象的方法实际传入的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//前置额外增强
System.out.println("前置增强....");
//目标对象的目标方法调用
Object o = method.invoke(us, args);//相当于mi.proceed();
System.out.println("后置增强.....");
//后置额外增强。
return o;
}
};
//3. 生成代理类,产生代理对象。
Object proxy = Proxy.newProxyInstance(us.getClass().getClassLoader(), us.getClass().getInterfaces(), handler);
System.out.println(proxy.getClass().getSimpleName());
UserService usproxy = (UserService) proxy;
usproxy.regist();
}
生成的代理类的庐山真面目
获得jvm中jdk动态代理生成的类
静态代理
代理类核心要素
1. 与目标对象拥有相同的方法。[继承目标类,覆盖父类的方法]
2. 额外功能代码。
3. 调用目标对象的方法。
静态代理第二种实现
目标类:
public class YellowLaodaye{
public void saleHouse() {
System.out.println("签合同,收钱,交易过程。");
}
}
代理类:
public class $Proxy1 extends YelloLaodaye{
@Override
public void saleHouse(){
System.out.println("1. 发广告!");
System.out.println("2. 看房子!");
System.out.println("3. 忽悠!");
//调用目标对象的方法。
super.saleHouse();
}
}
基于继承的静态代理
cglib的动态代理
cglib动态代理技术: 生成基于继承的代理类,及其对象。
编码
编码核心要素
cglib动态代理的编码步骤
1. 额外功能。 InvocationHander(cglib包下)
2. 目标对象。 YellowLaoDaye yld = ...;
3. 组装生成代理类
增强器: EnHancer
① 绑定父类。 YellowLaoDaye.class
② 组合额外功能。handler
③ 生成代理类的对象。eh.create();
示例代码:
//1. 目标对象
final YellowLaodaye yld = new YellowLaodaye();
//2. 增强功能
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//前置增强。
System.out.println("1. 发广告!");
System.out.println("2. 看房子!");
System.out.println("3. 忽悠!");
//调用目标对象的目标方法。
Object obj = method.invoke(yld, args);
return obj;
}
};
//3. 组装生成代理类的对象。
//0. 创建增强的组合器。
Enhancer eh = new Enhancer();
//① 绑定父类。
eh.setSuperclass(YellowLaodaye.class);
//② 绑定额外功能对象
eh.setCallback(handler);
//③ 生成代理类对象
Object proxy = eh.create();
//System.out.println(proxy.getClass().getSimpleName());
YellowLaodaye proxylaodaye = (YellowLaodaye) proxy;
proxylaodaye.saleHouse();
总结Springaop原理:
1. 本质:
借尸还魂 移花接木 李代桃僵。
为目标类,使用动态字节码技术(jdk动态代理,cglib动态代理)动态生成代理类,反射创建代理类的对象,替换原有的目标对象。
注释:
① 如果目标类有接口,spring默认会使用jdk动态代理,
② 如果目标类没有接口,但是能够被继承(没有被final修饰),spring会自动切换使用cglib动态代理技术,
③ 如果目标类,没有接口且被final修饰,无法完成代理类生成。
2. Jdk动态代理
基于接口的方式生成代理类。
要求: 目标类必须有接口。
3. Cglib动态代理
基于继承的方式生成代理类。
要求: 目标类必须能够被继承【不能用final修饰】
4. 补充:动态代理性能
Jdk版本每次更新,都会大幅度提升Jdk动态代理性能,jdk1.8以后,Jdk动态代理性能完胜cglib;