Spring 快速学习笔记
来源:互联网 发布:java的框架 编辑:程序博客网 时间:2024/05/01 20:37
以前的学习笔记,给翻了出来,分享一下。
spring:项目管理,管理项目中各个组件,为j2ee开发提供更好的解决方案。
spring:工厂,容器:项目中各个组件由spring负责创建,并保管,spring工厂是spring一切功能的支持。
1、.spring工厂搭建:
1>导包
2>配置:
名称:任意 applicationContext.xml beans.xml
位置:任意
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <!-- 声明bean,告知spring去生产如下的bean --> <bean id="userservice42" class="com.c42.service.UserServiceImpl"></bean> <bean id="userdao42" class="com.c42.dao.UserDAOImpl"></bean> </beans>
3>创建工厂:
ApplicationContext ClassPathXmlApplicationContext(本地测试) XmlWebApplicationContext(web环境) //创建工厂,并制定配置文件位置 ApplicationContext context=new ClassPathXmlApplicationContext("/com/c42/config/applicationContext.xml"); //从工厂中获取bean UserDAO ud=(UserDAO)context.getBean("userdao42"); ud.deleteUserById(1); UserService us=(UserService)context.getBean("userservice42"); us.deleteUserById(1);
工厂创建bean的原理:
反射+无参构造。
2、IOC:inverse of controll 控制反转
:将成员变量的赋值权由代码中反转到配置文件中,以注入(Deny Injection)的方式为成员变量赋值。 :使得具有依赖关系的双方耦合度降低。
class UserServiceImpl implements UserService{ private UserDAO ud; public UserDAO getUd() { return ud; } public void setUd(UserDAO ud) { this.ud = ud; } ... } <!-- 声明bean,告知spring去生产如下的bean --> <bean id="userservice42" class="com.c42.service.UserServiceImpl"> <!--依赖注入: 将id为userdao42的bean赋值给当前bean的名为ud的属性 --> <property name="ud" ref="userdao42"></property> </bean> <bean id="userdao42" class="com.c42.dao.UserDAOImpl"></bean>
3、set注入:通过set方法将属性值,注入属性。
<bean id="user42" class="com.c42.entity.User"> <!-- 普通类型注入:jdk8种+String --> <property name="id" value="1"></property> <property name="name" value="c42"></property> <property name="gender" value="true"></property> <!-- 引用类型 --> <property name="addr42" ref="addr42"></property> <!-- 集合/数组 --> <property name="objs42"> <list> <value>42</value> <value>c42</value> <ref bean="addr42"/> </list> </property> <!-- Map --> <property name="map42"> <map> <entry key="key1" value="true"></entry> <entry key="key2" value="c42"></entry> <entry key="key3" value-ref="addr42"></entry> </map> </property> <!-- properties --> <property name="prop42"> <props> <prop key="url">jdbc:oracle:xxxx</prop> <prop key="driver">oracle.jdbc.xxx</prop> <prop key="username">hr</prop> </props> </property> </bean>
4、构造注入:通过构造方法,将属性值,注入属性
<!-- 构造注入 --> <bean id="user43" class="com.c42.entity.User"> <constructor-arg index="0" type="java.lang.Integer" value="1"></constructor-arg> <constructor-arg index="1" type="java.lang.String" value="c43"></constructor-arg> <constructor-arg index="2" type="java.lang.Boolean" value="true"></constructor-arg> </bean>
*不够灵活*细节:如果在注入时,使用了构造注入,则在bean创建时,也会使用对应的构造方法,而不使用无参构造。
5、自动注入:spring工厂会按照某种规则,自动为bean中的属性注入值。
规则:byType/byName
*仅限自建类型,jdk类型无法自动注入。
<bean id="user44" class="com.c42.entity.User" autowire="byType"></bean> <bean id="user44" class="com.c42.entity.User" autowire="byName"></bean>
*byType:极易导致注入冲突。
*byName:可读性较差。
6.bean创建模式:默认单例模式
:工厂中的bean默认只创建一次,全局唯一。 :scope="prototype/singleton" 其中singleton为缺省值 非单例 单例
<bean id="user45" class="com.c42.entity.User"></bean> <bean id="user46" class="com.c42.entity.User" scope="prototype"></bean>
*注意:在将Action组件纳入工厂,务必要添加scope属性,控制创建模式为非单例的。
7.bean生命周期:
*何时创建:工厂创建时,所有的单例的bean随之创建。非单例的bean,在获取时创建。*何时销毁:工厂关闭,bean销毁。
<bean init-method="xx" destroy-method="xx"> <bean id="order42" class="com.c42.entity.Order" init-method="init42" destroy-method="destroy42"></bean>
bean中的任何一个方法都可以被指定为初始化和销毁方法。
8.类型转换器
在DI过程中,简单的类型转换,spring可以自动完成:String -- 数字/boolean
<bean id="user42" class="com.c42.entity.User"> <!-- 普通类型注入:jdk8种+String --> <property name="id" value="1"></property> <property name="name" value="c42"></property> <property name="gender" value="true"></property> <property name="birthday" value="2015-12-12"></property> </bean>
1>定义类:
extends PropertyEditorSupport{ /** * <bean id="user42" class="com.c42.entity.User"> <property name="birthday" value="2015-12-12"></property> </bean> param:text-->要类型转换的值:2015-12-12 */ @Override public void setAsText(String text) throws IllegalArgumentException { SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd"); Date ret=null; try { ret=format.parse(text); } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } this.setValue(ret);//将转换好的数据返回给spring } }
2>配置:将自定义的类型转换器交给spring
<!-- 类型转换器配置:声明转换器,将转换器交给spring --> <bean id="dateEditor42" class="com.c42.propetyEditor.DateEditor"></bean> <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="customEditors"> <map> <entry key="java.util.Date" value-ref="dateEditor42"></entry> </map> </property> </bean>
9、复杂对象创建:不能直接new,而需要一个较复杂的创建过程的对象。
1>implements FactoryBean<SessionFactory>{ /** * 主体逻辑:定制对象的创建过程 */ public SessionFactory getObject() throws Exception { Configuration cfg=new Configuration().configure(); return cfg.buildSessionFactory(); } /** * 返回目标类的类对象 */ public Class<?> getObjectType() { return SessionFactory.class; } /** * 决定所生产的bean是否是单例的 * true 单例 * false 非单例 */ public boolean isSingleton() { return true; } }
2>配置:
<!-- 声明FactoryBean --> <bean id="sessionFactory42" class="com.c42.factoryBean.MySessionFaocty"></bean> 3>使用: SessionFactory sf=(SessionFactory)context.getBean("sessionFactory42");
*注意:当获取的bean是FactoryBean的子类时,返回的不是bean本身的对象,而是该bean中 getObject方法的返回值。
10、spring初步整合hiberante
1>通过FactoryBean,定制SessionFactory
2>将Service纳入工厂
3>将DAO纳入工厂
4>满足依赖:
Service:DAO+SessionFactory DAO:SessionFactory
11、spring组件支持:LocalSessionFactoryBean定制,并引入连接池
<!-- 数据源 1--> <bean id="datasource42" class="org.apache.commons.dbcp.BasicDataSource"> <property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"></property> <property name="driverClassName" value="oracle.jdbc.OracleDriver"></property> <property name="username" value="hr"></property> <property name="password" value="hr"></property> <property name="initialSize" value="1"></property> <property name="maxActive" value="3"></property> <property name="maxWait" value="2000"></property> </bean> <bean id="sessionFactory42" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <!-- 数据源 --> <property name="dataSource" ref="datasource42"></property> <!-- hibernate自身属性 --> <property name="hibernateProperties"> <props> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop> <prop key="hibernate.current_session_context_class">thread</prop> </props> </property> <!-- 映射文件 --> <property name="mappingResources"> <list> <value>com/c42/config/user42.hbm.xml</value> </list> </property> <!-- <property name="mappingDirectoryLocations"> <list> <value>/com/c42/config</value> </list> </property> --> </bean>
12、AOP:面向切面 :代理模式–> 代理类
:切面=额外功能(Advice)+切入点(pointCut) :抽取业务中的冗余的额外功能,使得核心业务和额外功能解耦和
OOP:面向对象 : 类 对象 接口 继承 多态 封装
13、针对于业务层中
interface UserService{ public void update(); public void insert(); } class UserServiceImple implements UserService{ public void update(){ //核心内容:更新 } public void insert(){ //核心内容:插入 } }
//额外功能:
//事务管理,日志记录
静态代理类:
1.持有原始对象
2.持有额外功能
3.和原始类有统一套接口。
class UserServiceProxy implements UserService{ UserServiceImple us=new UserServiceImple(); public void update(){ //额外功能: //事务管理,日志记录 us.update(); //事务管理 } public void insert(){ //额外功能: //事务管理,日志记录 us.insert(); } }
14、动态代理搭建:
*准备原材料:1.原始业务类 2.额外功能
*额外功能组件:
MethodBeforeAdvice 前置额外功能 AfterReturningAdvice 后置额外功能 MethodInterceptor 环绕额外功能
*定制前置的额外功能:
implements MethodBeforeAdvice{ /** * 此方法会在核心业务方法之前执行。 * param: * method:执行的方法对象 * params:方法的参数表 如果空参方法,则params为length为0的数组 * target:原始对象 */ public void before(Method method, Object[] params, Object target) throws Throwable { System.out.println("method:"+method.getName()+" params's length"+params.length+" target:"+target); } }
*编织:指定组装规则,基于schema
<aop:config> <!-- 切入点:额外功能要追加到的业务方法位置。 execution表达式:切入点描述 返回值 包.类.方法名(参数表) * com.c42.service.UserServiceImpl.*(..) --> <aop:pointcut expression="execution(* com.c42.service.UserServiceImpl.*(..))" id="pc42"/> <!-- 组装 --> <aop:advisor advice-ref="before" pointcut-ref="pc42"/> </aop:config>
*获取代理类: 只需要通过原始类的BeanID,即可获取代理类对象。
15、额外功能(Advice:通知)
*MethodBeforeAdvice *AfterReturningAdvice implements AfterReturningAdvice{ /** * 在核心业务之后执行 * param: * ret:目标方法的返回值 如果是void 则ret为null * method:目标方法对象 * params:参数表 * target:目标,原始业务类 */ public void afterReturning(Object ret, Method method, Object[] params, Object target) throws Throwable { System.out.println("ret:"+ret+" method:"+method.getName()+" params's length:"+params.length+" target:"+target); } } *MethodInterceptor implements MethodInterceptor{ /** * 会在目标类的方法的前后都执行 * 注意:要接收核心业务结果,并返回。 */ public Object invoke(MethodInvocation mi) throws Throwable { System.out.println("tx begin~~~"); //调用目标类的方法(核心业务功能),并接收业务结果 Object ret=mi.proceed();//调用目标类的方法。 System.out.println("tx commit~~~"); return ret;//将核心业务功能的业务结果返回给用户。 } } *ThrowsAdvice implements ThrowsAdvice{ /** * 当目标类方法中抛出异常时执行 * @param ex 抛出的异常对象 */ public void afterThrowing(Exception ex){ System.out.println("msg:"+ex.getMessage()); } }
16、execution表达式:描述切入点(point-cut)
组成:[修饰符] 返回值 包.类.方法(参数表)
1> * com.c42.service.UserServiceImpl.query(..)
返回值:任意
包:com.c42.service
类:UserServiceImpl
方法:query
参数表:任意
2> * com.c42.service.UserServiceImpl.*(..)
返回值:任意
包:com.c42.service
类:UserServiceImpl
方法:任意
参数表:任意
3> * com.c42.service..(..)
返回值:任意
包:com.c42.service
类:任意
方法:任意
参数表:任意
4> * *(..)
返回值:任意
包:任意
类:任意
方法:任意
参数表:任意
5> * login(..)
返回值:任意
包:任意
类:任意
方法:login
参数表:任意
6> * com.c42.service.UserServiceImpl.query*(..)
* com.c42.service.UserServiceImpl.User(..)
返回值:任意
包:com.c42.service
类:UserServiceImpl
方法:query开头
参数表:任意
*建议execution表达式尽量精确。
17、动态代理的实现原理:
*jdk代理:目标类要有对应的接口实现。
: 通过和目标实现同样的接口保证有同样的功能实现。
*cglib代理:目标类不用有接口实现。
: 通过继承目标类,保证和目标有同样的功能实现。
*代理类定制阶段:jdk快于cglib
代理执行:cglib快于jdk
18、BeanPostProcessor(后处理bean):对bean再加工
:通过原始业务类的beanID,获取到的是代理类对象,就是因为,有后处理bean再加工了原始的业务bean
*Bean运转过程:
构造-->set--->postProcessBeforeInitialization --> init -->postProcessAfterInitialization -->用户
*定制类:
implements BeanPostProcessor{ /** * 在init方法之后执行 * param: * bean:是postProcessBeforeInitialization加工后的Bean对象 */ public Object postProcessAfterInitialization(Object bean, String ID) throws BeansException { System.out.println("afterInit~~~"); // TODO Auto-generated method stub return bean;//将bean返回给用户 } /** * 在init之前执行 * param: * bean:原始的bean对象 */ public Object postProcessBeforeInitialization(final Object bean, String ID) throws BeansException { System.out.println("before init~~~"); //对原始的bean进行再次加工: //1.准备额外功能 InvocationHandler ih=new InvocationHandler(){ /** * method:方法对象 * args:方法中参数 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("hh~~~"); Object ret=method.invoke(bean, args);//调用目标us的方法。 System.out.println("hh2!!!"); return ret; } }; //2.将原始的bean加工的代理对象 UserService usProxy=(UserService)Proxy.newProxyInstance( TestDynamicProxy.class.getClassLoader() , bean.getClass().getInterfaces() , ih ); return usProxy;//将加工后的bean返回给postProcessAfterInitialization } }
19、spring事务管理
*事务管理逻辑(并不是真正的事务管理器,需要进一步包装)
<bean id="txM" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory42"></property> </bean> **包装**<tx:advice transaction-manager="txM" id="txManager"> <tx:attributes> <!-- 以方法为单位管理事务,指定事务属性 --> <tx:method name="query*" propagation="SUPPORTS"/> <!-- *其余所有方法 --> <tx:method name="*" isolation="READ_COMMITTED" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/> </tx:attributes> </tx:advice>
事务属性: <!-- 基于schema包装事务管理器 事务属性: *读写性:read-only read-write :在只读事务中,只允许读取操作。 *传播性:required 如果检测到当前已有事务环境,则融入,如果没有则创建一个 supports 如果检测到当前已有事务环境,则融入,如果没有则在非事务环境下执行 *隔离级别:[读未提交],事务之间可以读到对方未提交的数据,会导致【脏读】。并发性最好。 [读提交],事务之间只能读到对方提交过的数据,可防止【脏读】,不能防止【不可重复读】,并发性较好。 [可重复读],在此隔离级别下,一个事务中,可以保证重复读取一条数据,结果一致,可防止【脏读】和【不可重复读】,不可防止【幻影读】,并发性较差。 [序列化读],在此隔离接下,可防止一切不合法的数据读取。并发性极差。 oracle中只实现了[度提交]和[序列化读],且[读提交]为oracle默认的隔离级别。 *脏读:一个事务中读取到了另外的事务中未提交的数据。 *不可重复读:一个事务中重复读取同一条数据,结果不一致 *幻影读:一个事务中重复读取某张表的数据,数据行数不一致。 *事务四个特性: 隔离 原子 一致 持久性 -->
19、引入了spring的hibernate事务管理支持之后,在定制SessionFactory时:
<!-- *如果有此配置: 则通过此SessionFactory.getCurrentSession()时,获取到的是hibernate维护的 线程唯一的session *如果没有此配置: 则通过此SessionFactory.getCurrentSession()时,获取到的是spring维护的 线程唯一的session --> <!-- <prop key="hibernate.current_session_context_class">thread</prop> -->5.资源网站: http://olex.openlogic.com
20、HibernateTemplate 简化DAO操作
<bean id="template42" class="org.springframework.orm.hibernate3.HibernateTemplate"> <property name="sessionFactory" ref="sessionFactory42"></property></bean>
*将template注入给DAO,完成CURD*HibernateTemplate: *get(); *load(); *find(hql); String hql="from User u order by u.id where id>? and id>? and id>? and name=?"; //return template.find(hql,1,2,3,"c42"); return template.find(hql,new Object[]{1,2,3,"c42"}); *save(); *update(); *delete(); *execute();
*注意:内部的doInHibernate方法的返回值,即execute方法的返回值
template.execute(new HibernateCallback<List<User>>(){ *//** * session 即当前线程中使用的session *//* public List<User> doInHibernate(Session session) throws HibernateException, SQLException { Query query=session.createQuery("from User u order by u.id"); query.setMaxResults(5); query.setFirstResult(0); return query.list(); } });
*注意:HibernateTemplate在做DAO操作时,将事务的自动提交设置为true ,便于单独测试DAO
21、SSH整合
*spring对于Hibernate整合:
*将DAO,Service纳入工厂
*通过LocalSessionFactoryBean创建SessionFactory,并引入连接池
*通过HibernateTransactionManager及schema:tx管理事务
*事务切入Service
*IOC满足依赖
*spring对于Struts2整合:
*将Action纳入工厂,并制定scope=prototype
*IOC满足依赖
*导入struts2-spring-plugin.jar
*配置Action时:
*工厂启动:
*在web.xml中配置ContextLoaderListener
*在web.xml中配置context-param指明spring配置文件的位置
22、配置信息分离
定义配置文件: url42=jdbc:oracle:thin:@localhost:1521:xe driverClass42=oracle.jdbc.OracleDriver username42=hr password42=hr initialSize42=1 maxSize42=3 maxWait42=2000引入配置文件: <!-- 引入外部的配置文件 --> <context:property-placeholder location="classpath:com/c42/config/db.properties"/>使用: <!-- 数据源 1--> <bean id="datasource42" class="org.apache.commons.dbcp.BasicDataSource"> <property name="url" value="${url42}"></property> <property name="driverClassName" value="${driverClass42}"></property> <property name="username" value="${username42}"></property> <property name="password" value="${password42}"></property> <property name="initialSize" value="${initialSize42}"></property> <property name="maxActive" value="${maxSize42}"></property> <property name="maxWait" value="${maxWait42}"></property> </bean>
23、OpenSessionInViewFilter:被此过滤器过滤的请求,请求中的session有此过滤器管理,
:保证事务提交后session依然是开启的; :在Jsp渲染期间session依然是开启,渲染完毕时关闭session*在web.xml中配置: <!-- 配置OpendSessionInViewFilter:处理延迟加载异常 --> <filter> <filter-name>osiv</filter-name> <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class> <!-- 将工厂中的sessionfactory的bean的Id交给此Filter 如果不指定,则此Filter会默认向工厂中索要一个ID为sessionFactory的bean --> <init-param> <param-name>sessionFactoryBeanName</param-name> <param-value>sessionFactory42</param-value> </init-param> </filter> <filter-mapping> <filter-name>osiv</filter-name> <url-pattern>/a</url-pattern> <url-pattern>/b/*</url-pattern> <url-pattern>/c/*</url-pattern> <url-pattern>/ssh/ssh</url-pattern> </filter-mapping> *不建议配置/*的url-pattern*注意:此过滤器务必要struts2的前端控制器之前。
24、注解Annotation
@Component(“userAction42”)
@Scope(“prototype”)
用在类上:用于声明bean,指定bean的创建模式
@Autowired
用在属性上:用于基于类型的自动注入
@Transactional(isolation=Isolation.READ_COMMITTED,rollbackFor=Exception.class,propagation=Propagation.REQUIRED,readOnly=false)
用在类上,或方法上,用于指定事务属性
*注意:使用注解,需要配置:
<!-- 编织:为service织入事务 --><bean id="txM" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory42"></property></bean><!-- 事务注解驱动 --><tx:annotation-driven transaction-manager="txM"/><!-- 用于告知spring哪些包中有注解需要解析 --><context:component-scan base-package="com.c42"></context:component-scan>
- Spring 快速学习笔记
- 学习笔记一:Spring Boot快速入门
- Spring学习笔记(3)----------Spring快速入门
- 使用 Spring Boot 快速构建 Spring 框架应用---学习笔记
- Spring学习笔记(3)——快速入门
- spring学习笔记(一)快速搭建一个spring boot应用
- 01.Spring Cloud学习笔记之使用IDEA+Spring Boot快速构建Rest服务
- Spring MVC快速入门笔记
- 快速排序学习笔记
- 学习笔记--快速排序
- Python快速学习笔记
- 快速排序学习笔记
- python快速学习笔记
- C++快速学习笔记
- 【学习笔记】快速幂
- 学习笔记快速记录
- Ajax快速学习笔记
- [Swift]:快速学习笔记
- 【Light-oj】-1138 - Trailing Zeroes (III)(二分,数学)
- 98. Validate Binary Search Tree
- GitHub常用开源框架
- c++模板的问题解析-问题2
- 边之比的平方=面积之比
- Spring 快速学习笔记
- JAVA深入研究——Method的Invoke方法。
- 分享一下书签
- Linux感悟-前言
- 使用javamail发送邮件
- 小鸡腿U T8 CERC2015
- [CF]Ilya and Queries
- hrbust 1759 Lawnmower【思维题】
- php.ini 中配置项的设置