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图):
执行结果:
分析:
执行所有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包下
- Spring
- Spring
- spring
- spring
- spring
- spring
- Spring
- spring
- spring
- Spring
- Spring
- spring
- Spring
- Spring
- spring
- spring
- spring
- Spring
- 你们也只剩下点赞的交情
- AndroidStudio1.5 安装完成后初次启动卡在download Components解决办法
- 排序-选择排序
- Struts2总结
- 2016.11.22 Java.lang.IllegalStateException
- Spring
- C++文件操作详解(ifstream、ofstream、fstream)
- 设计一个有getMin功能的栈
- “技能成就梦想 创新促进发展”2016年成德绵创新改革试验区第二届高技能人才交
- 将输入的制表符替换成适当数目的空格,使空格充满到下一个制表符终止的地方。
- Spring Boot 菜鸟教程 2 Data JPA
- Activiti 实现节点的循环
- try-catch-finally语句中用什么方法退出或者不执行finally就直接退出并且return和finally的执型顺序是怎样的
- 中国大学mooc程序设计入门C语言:素数和