Spring

来源:互联网 发布:数据库唯一性约束 编辑:程序博客网 时间:2024/05/17 02:29

IOC

xml配置bean

xml文件:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:context="http://www.springframework.org/schema/context"    xmlns:util="http://www.springframework.org/schema/util"    xmlns:p="http://www.springframework.org/schema/p"       xsi:schemaLocation="http://www.springframework.org/schema/beans         http://www.springframework.org/schema/beans/spring-beans.xsd        http://www.springframework.org/schema/util         http://www.springframework.org/schema/util/spring-util-4.0.xsd         http://www.springframework.org/schema/context                                   http://www.springframework.org/schema/context/spring-context-3.0.xsd">    <!-- 配置一个 bean。这里自动装配了Study,autowire可以是byName(id名与属性名对应)或者byType -->    <bean id="student" class="com.diyun.beans.Student"     autowire="byName"  init-method="init" destroy-method="destory">        <!-- 为属性赋值 ,通过调用无参构造器和setter-->        <property name="name" value="张三"></property>        <property name="sex" value="1"></property>        <!-- 如果不自动装配:关联id为study的bean,传递引用型变量          <property name="study" ref="study" >            <list><map><set>标签放在这里可以给集合赋值,           也可以用与<bean>同级的<util:*>标签把集合赋值提出来以供     复用 (通过id属性供ref调用)          </property>        -->     </bean>    <!-- 另一种配置方式 ,这里设置abstract="true",使得该bean无法被实例化(抽象bean),仅可作为模板供其他bean继承        如果一个bean没有class属性,则必须为抽象bean    -->    <bean id="student2"        p:name="李四"        p:study-ref="study" abstract="true">    </bean>    <!-- 继承复用study的配置,autowire装配的属性不会被继承         scope属性指明bean的作用域,取值有singleton(单例,每次返回同一个实例,在容器创建时就生成),prototype(每次创建新实例)    -->    <bean id="student3" parent="student" p:study-ref="study" scope="prototype"></bean>    <bean id="study" class="com.diyun.beans.Study"  init-method="init" destroy-method="destory"    depends-on="student"><!--depends-on属性设置依赖关系,实际上是指定Bean加载顺序(student先加载)  -->        <!-- 通过构造器赋值 -->        <constructor-arg name="yuwen" value="92"></constructor-arg>        <!-- 使用sqEL表达式,T()表示引用类的静态属性 -->        <constructor-arg name="shuxue" value="#{T(java.lang.Math).PI*4}"></constructor-arg>        <constructor-arg name="yingyu" value="#{student.sex==0?100:99}"></constructor-arg>    </bean>    <!-- 配置bean的后置处理器,该处理器实现了BeanPostProcessor接口 -->    <bean class="com.diyun.beans.MyBeanPostProcessor" ></bean>    <!-- 导入属性文件 -->    <context:property-placeholder location="classpath:db.properties"/>    <!-- 连接数据库 -->    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">               <property name="driverClass" value="${driverClass}" />              <property name="jdbcUrl" value="${jdbcUrl}" />              <property name="user" value="${user}" />              <property name="password" value="${password}" />          </bean>  </beans>

BeanPostProcessor接口对bean进行预处理(会处理所有bean):

package com.diyun.beans;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanPostProcessor;public class MyBeanPostProcessor implements BeanPostProcessor {    @Override    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {        System.out.println("after:"+bean+","+beanName);        return bean;    }    @Override    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {        System.out.println("before:"+bean+","+beanName);        if(bean instanceof Student){            ((Student) bean).setName("王二麻子");//在bean的 init执行前替换属性        }        return bean;    }}

调用:

ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext("applictionContext.xml");System.out.println("容器创建完毕");Student bean = (Student)ctx.getBean("student"); //对应配置文件中bean的ID//Student bean = ctx.getBean(Student.class);//另一种方式有限制,必须为唯一的beanSystem.out.println(bean.toString());//DataSource ds=(DataSource)ctx.getBean("dataSource");连接数据库//Connection c = ds.getConnection();//System.out.println(c);ctx.close();

关于执行顺序,看一下我demo的结构(不算是UML图):demo结构

执行结果:
执行结果

分析:
执行所有bean的构造函数(实例化)
->②(对第一个bean){ BeanPostProcessor接口的beforeInit
->xml里配置的init-method方法
->afterInit
->setter方法赋值(如果需要的话) }
->装配下一个bean(从②处开始)
- · · ->ApplicationContext加载完毕
- -> · · ·
- ->destory方法

其中,Student先于Study初始化并赋值,因为首先配置时设置了id为study的bean中有depends-on=”student”这一条属性(没有这条属性会报错),其次没有student.sex值的话,study.yingyu无法确定值为多少

注解配置bean

xml配置spring扫描组件的区域:

<context:component-scan base-package="com.diyun.annotation"         resource-pattern="/*" use-default-filters="true"><!-- 去除默认过滤器(设为false)的话,只扫描include-filter指定的包 -->        <!--<context:include-filter type="assignable" expression=""/> assignable表示expression指定的类(或接口)的所有扩展和实现         <context:exclude-filter type="annotation" expression=""/> annotation就是一个萝卜一个坑~ -->         </context:component-scan>    

demo:

@Component("a")////作用于类,作为spring扫描时的标识public class A {    @Autowired //自动装配,B类也有@Component注解    @Qualifier("b") //装配冲突时进行选择    private B b;    public void say() {        System.out.println("A");        b.say();    }}

spring支持泛型依赖注入,即为子类注入子类所需的依赖。首先要知道 @Autowired可以被继承到子类,看简易demo:

 class A<T>{@Autowired B b;} class B<T>{} @Component class Ason extends A<User>{} @Component class Bson extends B<User>{}

获取A的子类Ason,发现里面的成员变量是B的子类Bson。这有以下条件:
1. 两个父类不被spring扫描,而两个子类被扫描
2. 两个子类泛型相同(demo中同为User)
3. @Autowired写在父类,并继承到了子类

其他:
@Service用于标注业务层组件

@Controller用于标注控制层组件(如struts中的action)

@Repository用于标注数据访问组件,即DAO组件

@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。

AOP

其实这玩意就是动态代理的简化版本

xml配置:

 <context:component-scan base-package="com.diyun.*"></context:component-scan>        <aop:aspectj-autoproxy></aop:aspectj-autoproxy><!--配置自动为匹配 aspectJ注解的 Java 类 生成代理对象-->     <!--         以下为xml配置aop:    <bean id="arithmeticCalculator"         class="com.diyun.aop.xml.ArithmeticCalculatorImpl"></bean>    //配置切面的 bean     <bean id="loggingAspect"        class="com.diyun.spring.aop.xml.LoggingAspect"></bean>    <bean id="vlidationAspect"        class="com.diyun.spring.aop.xml.VlidationAspect"></bean>      // 配置 AOP    <aop:config>         //配置切点表达式        <aop:pointcut expression="execution(* com.diyun.spring.aop.xml.ArithmeticCalculator.*(int, int))"             id="pointcut"/>         //配置切面及通知        <aop:aspect ref="loggingAspect" order="2">            <aop:before method="beforeMethod" pointcut-ref="pointcut"/>            <aop:after method="afterMethod" pointcut-ref="pointcut"/>            <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="e"/>            <aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/>            <aop:around method="aroundMethod" pointcut-ref="pointcut"/>        </aop:aspect>           <aop:aspect ref="vlidationAspect" order="1">            <aop:before method="validateArgs" pointcut-ref="pointcut"/>        </aop:aspect>    </aop:config>     -->   

注解配置:

//@order(int)指定切面优先级@Aspect@Componentpublic class MyAspect {    //定义一个切点    @Pointcut("execution(public int com.diyun.aop.Jisuan.divide(int,int))")    public void pointcutExpression(){}    /*@Before("execution(public * com.diyun.aop.Jisuan.*(..))")        匹配com.diyun.aop.Jisuan类里任意返回值,任意方法名,任意参数列表*/    @Before("execution(public int com.diyun.aop.Jisuan.divide(int,int))")    public void before(JoinPoint joinPoint){//JoinPoint能获取方法信息        String methodName=joinPoint.getSignature().getName();        Object[] args=joinPoint.getArgs();        System.out.println(methodName+"("+args[0]+"/"+args[1]+")");    }    //@After 后置通知无论方法是否抛出异常;无法获取方法执行结果    //@AfterRunning 返回通知    //使用表达式代替了重复书写方法信息,不同包之间可以通过添加包名来传递    @AfterThrowing(value="pointcutExpression()",throwing="e")    public void afterThrowing(JoinPoint joinPoint,NullPointerException e){//只执行指定异常        System.out.println(e.getMessage());    }    /*     * 环绕通知类似于动态代理全过程     */    @Around("pointcutExpression()")    public Object around(ProceedingJoinPoint pjp){        Object result=null;        try {            //前置通知            result=pjp.proceed();//执行目标方法        } catch (Throwable e) {            //异常通知        }finally{            //后置通知        }        //返回通知        return result;    }

通过aop为类动态引入新方法

@Aspect@Componentpublic class DoAspect {    //通过切面引入新方法(实际上就是通过切面添加新的接口,并绑定一个该接口的实现类,从而实现添加新方法)    @DeclareParents(value="com.diyun.*"/*需要添加新方法的类*/,defaultImpl=TestClass.class/*方法实现类,该类肯定要实现Extra的接口*/)    public static Extra extra;/*接口名*/}

Spring事务处理

Spring jdbc有点简洁过头

配置:

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">    <property name="user" value="${jdbc.user}"></property>    <property name="password" value="${jdbc.password}"></property>    <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>    <property name="driverClass" value="${jdbc.driverClass}"></property>    <property name="initialPoolSize" value="${jdbc.initialPoolSize}"></property>    <property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property></bean><bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">    <property name="dataSource" ref="dataSource"></property></bean>

调用:

DataSource dataSource=(DataSource)ctx.getBean("dataSource");//JdbcTemplate template=new JdbcTemplate(dataSource);//RowMapper rowMapper=new BeanPropertyRowMapper(UserInfo.class);//列的别名实现从列名到属性名的映射//UserInfo user=template.queryForObject("select id,username,password pwd from user_info where id=?",rowMapper,6);//template.update(sql); 执行insert,delete,update//template.batchUpdate(sql, batchArgs); 批量执行insert,delete,update//NamedParameterJdbcTemplate支持具名参数,通过在sql中使用":变量名"来对应相应的变量(就是占位符对应的序号换成变量名,这样不容易出错)

启用事务

加入配置:

<!-- 事务管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">    <property name="dataSource" ref="dataSource"></property></bean><!-- 启用事务注解 --><tx:annotation-driven transaction-manager="transactionManager" />

·使用:

/* @Transactional属性: *  1.propagation:涉及到事务传播行为时(一个事务包含另外一个事务时), *   REQUIRES_NEW是部分回滚(能买多少是多少);REQUIRED是整体回滚(都买不成) *  2.isolation:事务的隔离级别,一般是READ_COMMITTED *  3.noRollbackFor/noRollbackForClassName:设定不回滚的选项 *  4.readOnly:只读事务时设置该属性为true,便于spring自动调优 */@Transactional(propagation=Propagation.REQUIRES_NEW)public void py(int cost) throws Exception{    updateSell(cost);    updateBuy(cost);}

xml配置事务:

<!-- 配置事务属性 --><tx:advice id="txAdvice" transaction-manager="transactionManager">    <tx:attributes>        <!-- name属性写方法名 -->        <tx:method name="*" propagation="REQUIRED" read-only="false"/>        <!-- 支持通配符,如get*代表所有get开头的方法 -->         <tx:method="get*"    </tx:attributes></tx:advice><!-- 配置事务切入点,并关联事务属性 --><aop:config>    <aop:pointcut expression="execution(* com.diyun.dao.DemoDao.py(..))" id="ex"/>    <aop:advisor advice-ref="txAdvice" pointcut-ref="ex"/></aop:config>

Spring应用于web

对于IOC容器,非web应用直接在main方法里创建了,那web应用呢?应该在web应用被服务器加载时创建。
为此,我们可以在ServletContextListener#contextInitialized方法中创建IOC容器,并把它放在ServletContext(即application域)中。
当然,这些代码其实spring帮我们写好了,直接在web.xml中引入:

 <listener>    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>

然后在servlet中:

ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(context);

其他

1.profile:控制bean的开闭,通过@profile(“name”)或beans的profile属性设置;有很多方式可以激活,如:
(ps:spring.profiles.active优于spring.profiles.default)

<context-param>    <param-name>spring.profiles.default</param-name>    <param-value>name1,name2</param-value></context-param>

方式:

  • 作为SpringMVC中的DispatcherServlet的初始化参数
  • 作为Web 应用上下文中的初始化参数
  • 作为JNDI的入口
  • 作为环境变量
  • 作为虚拟机的系统参数
  • 使用@AtivceProfile()来进行激活(作为JUnit测试时使用)

2.SpEL(如果使用注解配置,可以在@Value中使用)

  • “ .?”:对集合进行过滤,生成新的子集,如#{songs.?[singer eq ‘周杰伦’]};
  • “?.”:防止级联时出现null,会有一个检查,如#{songs?.singer}
  • “.^”/ “.$”:查询集合中第一个/最后一个匹配项,如#{songs.^[singer eq ‘周杰伦’]},返回周杰伦的第一首歌曲
  • “.!”:将集合属性投影到另一个集合,如#{songs.![singer]},返回歌手集合
  • “T()”:调用api,如#{T(java.util.Math).random()}

3.AspectJ切点表达式:除了execution,还有

  • args() 限制连接点匹配参数为执行类型的执行方法
  • @args() 限制连接点匹配参数由执行注解标注的执行方法
  • execution() 匹配连接点的执行方法
  • this() 限制连接点匹配AOP代理的Bean引用类型为指定类型的Bean
  • target() 限制连接点匹配目标对象为指定类型的类
  • @target() 限制连接点匹配目标对象被指定的注解标注的类
  • within() 限制连接点匹配匹配指定的类型
  • @within() 限制连接点匹配指定注解标注的类型
  • @annotation 限制匹配带有指定注解的连接点

操作符:“||/or”,“&&/and”,“!/not”

用法举例:

- execution("* *.*(..)"):匹配所有- execution("* *.set*(..)):匹配所有以set开头的方法- execution("* com.david.biz.service.impl.*(..)):匹配指定包下所有的方法- execution("* com.david..*(..)"):匹配指定包以及其子包下的所有方法- execution("* com.david..*(java.lang.String)):匹配指定包以及其子包下参数类型为String 的方法- execution("* com.diyun.*(..) && within(com.diyun.*))":用within限制匹配,该句限制必须在com.diyun包下
0 0
原创粉丝点击