Spring

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);//另一种方式有限制,必须为唯一的bean
System.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
@Component
public 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
@Component
public 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值