SSM Spring
Spring
分层的java se/ee 应用 全栈式 轻量级开源框架
- 全栈式:对主流技术和框架进行整合,对三层架构提供了解决方案
- 轻量级:使用了多少服务,启动加载的资源多少以及耦合度等
Spring :IOC AOP 两大核心
- IOC:控制反转, 对象的创建权 交给 spring
- AOP :面向切面编程,不修改源码,对方法增强
spring优势
- 方便解耦,简化开发。
- 耦合,指对象的依赖关系,一个模块更改其他模块也需要更改。
- 解耦,降低程序间的依赖关系。配置文件+反射
- AOP编程支持
- 声明式事务的支持,通过配置
- 方便测试
- 方便集成各种框架
IOC
控制反转
控制:java对象的控制权限(对象的创建,销毁)
反转:对象的控制权限由开发者类中手动创建反转到spring容器控制
// spring上下文对象,加载的同时创建了bean对象到容器中
//aplicationContext.xml核心配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationCOntext.xml");
context.getBean("userDao");
Spring API
BeanFactory 和ApplicationContext区别
BeanFactory 第一次被调用 getBean()才会创建Bean对象
ApplicationContext 类加载的同时,创建了bean对象到容器中
BeanFactory实现类
- FileSystemXmlApplicationContext,磁盘路径,绝对路径
- ClassPathXmlApplicationContext ,类的根路径下加载
- AnnotationCOnfigApplicationContext
getBean重载方法
- getBean(String id)
- getBean(Class<T> requireType)
- getBean(String id,Class<T> requireType)
spring配置文件
bean标签
<bean id=“” class=“完全类名” scope=“” init-method=“初始化方法名” destroy-method=“销毁方法”>默认调用无惨构造
scope取值:
- singleton 默认,单例,生命周期与容器相同
- prototype 多例,调用getBean()方法时才实例化
Bean生命周期
init-method 对象创建后执行 init-method
实例化方式
- 工厂静态方法
// class staticFactory 调用factroy-method
<bean id="userDao" class="com.lagou.factory.StaticFactory" factory-method="createUserDao" ></bean>
- 工厂普通方法
先生成工厂实例,再调用方法生成其他实例
<bean id="dynamicBean" class="com.lagou.factory.DynamicFactoryBean" ></bean>
<bean id="userDao" factory-bean="dynamicBean" factory-method="createUserDao" ></bean>
DI 依赖注入
对象注入
构造方法
<bean id="" class="">
<!-- 0 第一个参数-- >
<constructor-arg index="0" type="com.lagou.dao.IUserDao" ref="userDao"/>
<!-- name代表构造方法中的参数名称-- >
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>
set方法
<bean id="userService" class="com.lagou.userService">
<!-- name属性的值 对应 setUserDao()方法名,ref用于引用类型,ref的值和引用类型id相同-->
<property name="userDao" ref="userDao"></property>
</bean>
ref和id一致吗?
P命名空间注入
普通数据类型注入
<bean id="userService" class="com.lagou.userService">
<!-- value用于普通数据类型-->
<property name="username" value="zhangfei"></property>
<property name="age" value="18"></property>
</bean>
集合数据类型注入
...
<property name="list">
<list>
<value>aaa</value>
<ref bean="user"></ref>
</list>
</property>
<!-- map-- >
<property name="map">
<map>
<entry key="k1" value="ddd"></entry>
</map>
</property>
<!-- properties-- >
<property name="map">
<props>
<prop key="k1">value1</prop>
</props>
</property>
配置文件模块化
导入spring分文件
<import resource=“application-service.xml”></import>
加载jdbc.properties
<context:property-placeholder location=“classpath:jdbc.properties”></context:property-placeholder >
Spring注解
注解扫描开启
<contex:component-scan base-package="com.lagou"></context:component-scan>
配置了 <bean>标签,生成类的实例对象到IOC容器
@Component
@Controller
@Service
@Repository
<property>标签,依赖注入
@AutoWired 根据引用类型完成依赖注入
@Qualifier 结合@AutoWired使用,再根据名称查找
@Resource(name=“”)
@Value 普通类型
bean的作用范围
@Scope <bean scope=“”/>
@Service("accountService") value值相当于 bean标签 id值
@Configuration 配置类
@Configuration
@ComponentScan("com.lagou")
@PropertySource(value="classpath:jdbc.properties") // value可以省略,只有一个值,且是value
public class SpringConfig {
@Value("${jdbc.driverClassName}")
private String driver
...
// key默认是方法名
@Bean("dataSouce")
public DataSouce getSouce(){
...
}
@Bean
public QueryRunner getQueryRunner(@Autowired DataSource datasouce) {
...
}
}
Spring注解Junit
// 指定junit运行环境
@RunWith(SpringJunit4ClassRunner.class)
// 指定配置类或配置文件
@ContextConfiguration(classes={SPringConfig.class})
@ContextConfiguration({"classpath:applicationContext.xml"})
AOP
- 获取数据库连接,和线程绑定
// ThreadLocal 线程存储类,key 是当前线程
ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
// 获取存储的值
threadLocal.get()
// 设置存储的值
threadLocal.set(conn)
// 删除存储的值
threadLocal.remove()
- 释放资源
/*手动事务改成自动提交事务
连接归还到连接池
解除线程绑定
*/
conn.setAutoCommit(true);
conn.close()
// 调用threadlocal remov()方法
connutils.remove();
动态代理
JDK代理 基于接口
CGLIB 代理基于父类
/* JDK动态代理
* ClassLoader loader,类加载器,获取代理对象的类加载器
* Class<?>[] interfaces ,被代理对象所需要实现的全部接口
* InvocationHandler h,代理对象调用任意方法,都会执行
* InvocationHandler的invoke 方法
*/
Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
/*
* proxy ,当前代理对象引用
* method, 被调用方法的引用
* args,被调用目标方法的参数
*/
Object invoke(Object proxy,Method method,Object[] args)
method.invoke(accountService,args);
/* cglib 代理
* 参数1,目标类字节码对象
* 参数2,动作类,代理对象调用目标对象的方法,会执行inetrcept方法
*/
Enhancer.create(accountService.getClass(),new MethodIntercepstor(){
/* o代表生成的代理对象,method:目标方法的引用,objects:目标方法参数, methodProxy 代理方法
*/
@Override
public Object intercept(Object o,Method method,Object[] objects,MethodProxy methodProxy) throws Throwable
// methodProxy.invokeSuper(o,objects),调用代理方法的父类方法
method.invoke(accountService, objects);
})
AOP优点
- 运行期间,不修改源码,功能增强
- 逻辑清晰
- 减少重复复代码
AOP对动态代理进行了封装,配置的方式对目标进行增强
AOP术语
- Target 被代理类
- Proxy 生成的代理对象
- Joinpoint (连接点) :可以被拦截增强的方法
- Pointcut(切入点):真正被拦截增强的方法
- Advice(通知/增强):增强的业务逻辑,
- 前置通知
- 后置通知
- 异常通知
- 最终通知
- 环绕通知,spring提供的通过代码的方式来手动控制 通知的类型
- Aspect(切面),切入点和通知的结合
- Weaving(织入) ,增强 应用到目标对象的过程,创建新的代理对象
<aop:config>
<aop:pointcut id="myPoint" expression="execution(public void com.lagou.service.impl.AccountServiceImpl.*(..)"></aop:pointcut>
<aop:aspect ref="myAdvice">
<!--execution([修饰符] 返回类型 包名.类名.方法名(参数)) -->
<!-- 目标类的transfer方法,使用myAdvice before方法前置增强 -->
<aop:before method="before" pointcut="execution(public void com.lagou.service.impl.AccountServiceImpl.transfer())"></aop:before>
<aop:after-returning point-ref="myPoint"></aop:after-returning>
</aop:aspect>
</aop:config>
xml配置AOP
execution([修饰符] 返回类型 包名.类名.方法名(参数))
1.访问修饰符可以省略
2. 返回值类型,包名,类名,方法名可以用 *匹配
execution(* *.*.*.*())
3.包名和类名中间一个点 . 代表当前包下的类,两个点.. 代表当前包及其子包的类
execution(* *..*.*())
4. 参数列表 .. 表示任意个数,任意类型的参数
execution(* *..*.*(..))
环绕通知
<aop:around method=“around” point-ref=”myPoint”/>
public Object around(ProceedingJoinPoint pjp) {
Object processed = null;
try {
System.out.println("前置");
//切点方法执行
processed = pjb.processed();
System.out.println("后置");
} catch(Exception e) {
System.out.println("异常");
} finall {
System.out.println("最终");
}
}
AOP注解
@Component
@Aspect // 升级为切面类
public class MyAdvice {
// 配置切入点和通知
@Before("execution(* com.lagou.service.impl.AccountServiceImpl.*(..))")
public void before() {
...
}
}
/applicationContext.xml/
<!--组件扫描-->
<context:component-scan base-package="com.lagou"/>
<!--aop的自动代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<bean id="accountService" class="com.lagou.service.impl.AccountServiceImpl"></bean>aop中配置的作用是代理类通过反射获取被代理对象的Class ,接口,方法等
Spring JDBCTemplate
JDBCTemplate jdbc= new JDBCTemplate(DataSource dataSource);
int update(sql,params); //执行增、删、改语句
List<T> query(sql,new BeanPropertyRowMapper<>(User.class)); //查询多个
T queryForObject(sql,new BeanPropertyRowMapper<>(User.class),params); //查询一个
new BeanPropertyRowMapper<>(); //实现ORM映射封装
事务
-
编程式事务
- PlatformTransactionManager接口 spring事务管理器
-
声明式事务
事务的传播
定义:一个业务方法被另一个方法调用,如何进行事务控制
REQUIRED
如果没有事务,就新建事务;如果已经存在事务,加入到事务中。被调用的方法必须进行事务控制
SUPPORTS
当前没有事务,以非事务进行。有事务,加入事务。当前被调用的方法有没有事务都可以执行(查询操作)
事务管理器通过读取事务定义参数进行事务管理,然后会产生一系列的事务状态。
<!--通知-->
<tx:advice id="txAdvice" transaction-manager="transactionmanger">
<tx:attributes>
<!-- name切点方法名称 com.lagou.service..*.*(..)中的方法,联系aop:advisor起来看-->
<tx:method name="*"/>
</tx:attributes>
</tx:advic>
<!--aop配置-->
<aop:config>
<!--切面配置-->
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.lagou.serivce..*.*(..))">
</aop:advisor>
</aop:config>
平台事务管理器
事务通知配置
事务注解驱动配置(xml 或注解)
Spirng ApplicationContext
ServletContextListener 监听器监听web应用启动,加载Spring配置文件,创建ApplicationContext,存储到servletContext域中
ApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(request.getServletContext());
Account account = (Account) webApplicationContext.getBean("account");