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>
0 0
原创粉丝点击