Spring框架之IoC和AOP
Spring框架简介:
2003年2月,Spring框架正式成为一个开源项目,并发布于SourceForge中。致力于Java EE应用的各种解决方案,而并不是仅仅专注于某一层的方案,是企业应用开发的“一站式”选择。贯穿表现层,业务层,持久层,并不取代已有的框架,而是以高度的开放性与它们无缝整合。
注:首先通过Spring官网的地址http://repo.spring.io/replease/org/springframework/spring/下载所需版本的spring资源。
Spring IoC:
Ioc:控制反转,也称为依赖注入,是面向对象的一种设计理念,用来降低程序代码之间的耦合度。
控制反转(依赖注入):容器(如Spring)负责把组件所依赖的具体对象注入(赋值)给组件,从而避免以硬编码的方式耦合在一起。
使用Ioc注入:
导入所需jar包,创建spring核心配置文件:
<?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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd "> </beans>
1.设值注入:
1 <bean id = "helloSpring" class="cn.demo.HelloSpring"> 2 <property name="str" value="Spring"></property> 3 </bean>
id:为其指定一个用来访问的唯一名称,如果想指定更多的别名,可以通过name属性,用逗号,分号,空格进行分隔。
class:要注入的类的完全限定名。
property:
name:属性的setter的方法名,所以使用设值注入必须提供setter方法。
value:赋给属性的值。
2.构造注入:使用构造方法进行赋值。
1 <bean id="user" class="cn.bdqn.pojo.User"> 2 <constructor-arg index="0" name="id" value="1" type="integer"></constructor-arg> 3 <constructor-arg index="1" name="name" value="Spring"></constructor-arg> 4 </bean>
constructor-arg:表示构造方法的一个参数,使用时不区分顺序。
index:参数的下标。(下标从0开始)
name:参数的名称。
value:赋予参数的值。
type:参数的类型。
使用时,无需全部指定以上属性。根据需求选择属性进行注入。
3.使用p命名空间实现属性注入:
<bean id="userDao" class="cn.dao.imp.UserDaoImp"></bean>
<bean id="user" class="cn.pojo.User" p:id="1" p:name="Spring" p:dao-ref="userDao"></bean>
p:属性名 = "属性值"
p:属性名-ref = "Bean的id"
使用p命名空间实现注入,也是通过属性的setter方法进行注入。必须提供该属性的setter方法。
测试注入的结果:(编写测试类)
1 package cn.test; 2 3 import org.springframework.context.ApplicationContext; 4 import org.springframework.context.support.ClassPathXmlApplicationContext; 5 import cn.bdqn.pojo.User; 6 import cn.bdqn.service.IUserService; 7 import cn.bdqn.service.imp.UserServiceImp; 8 9 10 public class test { 11 public static void main(String[] args) { 12 ApplicationContext c = new ClassPathXmlApplicationContext("app.xml");//读取Spring核心配置文件 13 User user = (User) c.getBean("user");//通过bean的id获取该类的实例对象 14 //输出类注入的属性值。例:user.getName();//读取user类中name的值。
15 } 16 }
在Spring中,bean可以被定义为两种模式:prototype(多例)和singleton(单例)
singleton(单例):只有一个共享的实例存在,所有对这个bean的请求都会返回这个唯一的实例。
prototype(多例):对这个bean的每次请求都会创建一个新的bean实例,类似于new。
Spring bean 默认是单例模式。可以通过 scope="prototype" 修改为多例模式。
<bean id="user" class="cn.pojo.User" scope="prototype">
注入不同的数据类型:
1.注入直接量(基本数据类型、字符串):
对于基本数据类型,及其包装类、字符串,除了可以使用value属性,还可以通过<value>子元素进行注入。
1 <property name = "name"> 2 <value>张三</value> 3 </property>
如果属性值中包含了XML中的特殊字符(&、<、>、"、')则注入时需要处理:
1.使用<[!CDATA[]]>标记
1 <property name = "name"> 2 <value><![CDATA[P&G]]></value> 3 </property>
2.把特殊字符替换为实体引用。
1 <property name = "name"> 2 <value>P&G</value> 3 </property>
XML预定的实体引用:
< :&It; > :> &:& ':' " :"
注:XML中仅有 < 和 & 是非法的,其他三个是合法的,但是替换为实体引用是个好习惯。
2.引用其他Bean组件:
Spring中定义的Bean可以相互引用,从而建立依赖关系,除了使用ref属性,还可以通过<ref>子元素实现。
<property name = "dao"> <!-- 引用id为userDao的对象为userService的dao属性赋值 --> <ref bean = "userDao"> </property>
<property name = "dao"> <!-- 引用id为userDao的对象为userService的dao属性赋值 --> <ref local= "userDao"> </property>
local属性和bean属性的用法几乎一致,都是用来指定要引用Bean的id。区别在于,Spring配置文件是可以拆分多个的。使用local属性只能在同一个配置文件中检索id,而使用bean属性可以在其他配置文件中检索bean的id。
3.使用内部Bean:
如果一个Bean组仅在一处需要使用,可以把它定义为内部Bean。
<!-- 为userService的dao属性赋值,调用的是serDao方法 --> <property name = "dao"> <!-- 定义userDao对象(这个userDaoImp只能被这个userService使用,无法被其他的Bean调用) --> <bean class="dao.imp.UserDaoImp"/> </property>
4.注入集合类型的属性:
1.注List或者数组类型的属性,可以使用<list>标签注入。
<property name = "list"> <list> <!-- 定义list或数组中的元素 --> <value>集合1</value> <value>集合2</value> </list> </property>
注:list标签中可以使用value、ref等标签进行注入集合元素,甚至是一个list标签。
2.对于set,可以使用set标签进行注入。
<property name = "set"> <set> <!-- 定义set中的元素 --> <value>集合1</value> <value>集合2</value> </set> </property>
注:set标签中可以使用value、ref等标签进行注入集合元素。
3.对于Map类型的属性。
1 <property name = "map"> 2 <map> 3 <!-- 定义map中的键值对 --> 4 <entry> 5 <key><value>map的键1</value></key> 6 <value>map的值1</value> 7 </entry> 8 9 <entry> 10 <key><value>map的键2</value></key> 11 <value>map的值2</value> 12 </entry> 13 </map> 14 </property>
注:如果map中的键或者值是Bean对象,可以把上述代码中的value换成ref。
4.对于Properties类型的属性。
<property name = "prop"> <props> <!-- 定义Properties中的元素 --> <prop key = "键1">值1</prop> <prop key = "键2">值2</prop> </props> </property>
注:Properties中的键和值通常都是字符串类型。
5.注入null和空字符串值
<!-- 注入空字符串值 --> <property name = "id"><value></value></property> <!-- 注入null值 --> <property name = "name"><null/></property>
-----------------------------------------------------------------------------------------------------------------------------------------------
Spring AOP:
面向切面编程:是软件编程思想发展到一定的阶段的产物。是面向对象的有益补充。一般用于具有横切逻辑的场合,如范围控制、事务管理、性能检测等。面向切面简单来说就是在不改变源程序的基础上为代码段增加一些新的功能,对代码段进行增强处理。设计思想来源于代理设计模式。
切面(Aspect):一个模块化的横切逻辑(或横切关注点),可能会横切多个对象。
连接点(Join Point):通过连接点找到切点的位置。
增强处理(Advice):散布在系统中的公共功能。日志管理 事务管理。
切入点(Pointcut):增强的代码需要放入的位置。
目标对象(Target object):被一个或多个切面增强的对象.
AOP代理(AOP proxy):由AOP框架所创建的对象,实现执行增强处理方法等功能。
织入(Weaving):将增强处理代码连接到应用程序中的类型或对象的过程。
增强类型处理:前置增强、后置增强、环绕增强、异常抛出增强、最终增强等类型。
注:切面可以理解成由增强处理和切入点的组成,既包含了横切逻辑的定义,也包含了连接点的定义。面向切面编程主要关心两个问题,一个是在什么位置,二是执行什么功能。Spring AOP是负责实施切面的框架。即由AOP完成织入工作。
1.使用AOP进行增强处理:
1.定义增强类:
1 package cn.bdqn.advice; 2 3 import org.apache.log4j.Logger; 4 import org.aspectj.lang.JoinPoint; 5 import org.aspectj.lang.ProceedingJoinPoint; 6 7 public class ServiceLoggingAdvice { 8 private Logger logger = Logger.getLogger(ServiceLoggingAdvice.class); 9 10 //前置增强 11 public void before(JoinPoint joinPoint){ 12 String methodName = joinPoint.getSignature().getName();//获得增强的方法名 13 String className = joinPoint.getTarget().getClass().getSimpleName();//获得增强的类名 14 logger.debug("前置增强。。。。"); 15 } 16 17 18 //后置增强 19 public void after(JoinPoint joinPoint){ 20 String methodName = joinPoint.getSignature().getName();//获得增强的方法名 21 String className = joinPoint.getTarget().getClass().getSimpleName();//获得增强的类名 22 logger.debug("后置增强。。。。"); 23 } 24 25 //异常增强 26 public void thowing(Exception e){ 27 logger.debug(e.getMessage()); 28 } 29 30 //最终增强 31 public void afterEnd(JoinPoint joinPoint){ 32 String methodName = joinPoint.getSignature().getName();//获得增强的方法名 33 String className = joinPoint.getTarget().getClass().getSimpleName();//获得增强的类名 34 logger.debug("最终增强"); 35 } 36 37 //环绕增强 38 public Object round(ProceedingJoinPoint joinPoint){ 39 Object result = null; 40 try { 41 logger.debug("环绕增强----前置"); 42 result = joinPoint.proceed(); 43 logger.debug("环绕增强---后置"); 44 } catch (Throwable e) { 45 e.printStackTrace(); 46 } 47 return result; 48 } 49 }
注:通过JoinPoint连接点可以获取目标方法的有关信息,如所在类,方法名,方法的访问修饰符等信息。
环绕增强方法声明ProceedingJoinPoint类型的参数,可以获取连接点的信息,方法与JoinPoint相同。是JoinPoint的子接口,其不但封装目标方法,以及目标参数,还封装了被代理的目标对象,通过它的proceed()方法可以调用真正的目标方法,从而达到对连接点的完全控制。
2.Spring配置文件进行AOP相关配置:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans 3 xmlns="http://www.springframework.org/schema/beans" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xmlns:p="http://www.springframework.org/schema/p" 6 xmlns:aop="http://www.springframework.org/schema/aop" 7 xsi:schemaLocation="http://www.springframework.org/schema/beans 8 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 9 http://www.springframework.org/schema/aop 10 http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 11 "> 12 13 <!-- AOP --> 14 <!-- 增强类 --> <bean id="advice" class="cn.bdqn.advice.ServiceLoggingAdvice"></bean> 15 <aop:config> 16 <aop:pointcut expression="execution(* cn.bdqn.service..*.*(..))" id="point"/> 17 <aop:aspect ref="advice"> 18 19 <!-- 前置增强 <aop:before method="before" pointcut-ref="point" /> --> 20 <!-- 异常抛出增强 <aop:after-throwing method="afterThrowing" pointcut-ref="point" throwing="e"/> --> 21 <!-- 最终增强 <aop:after method="afterEnd" pointcut-ref="point"/> --> 22 <!-- 后置增强 <aop:after-returning method="after" pointcut-ref="point"/> --> 23 <!-- 环绕增强 <aop:around method="around" pointcut-ref="point"/> --> 24 </aop:aspect> 25 </aop:config> 26 </beans>
1.前置增强:使用<aop:before>进行前置增强,在目标方法前执行。
2.后置增强:使用<aop:after-returning>进行后置增强,在目标方法之后执行。(如果目标方法出现异常,无论是否使用try-catch捕获,后置增强都不会执行)
3.异常抛出增强:使用<aop:after-throwing>进行异常抛出增强,在目标方法抛出异常时,织入增强代码。
4.最终增强:使用<aop:after>进行最终增强。(如果目标方法出现异常,无论是否使用try-catch捕获,最终增强都会执行)
5.环绕增强:使用<aop:round>进行环绕增强,在目标方法前后都可以织入增强处理。功能最为强大的增强处理类型,Spring把目标方法的控制权全部交给了它,环绕增强处理中,可以获取或者修改目标方法的参数,返回值,可以进行异常处理,甚至可以决定目标方法是否被执行。
注:配置切入点的标签<aop:pointcut>的expression的属性可以配置切入点的表达式:
execution是切入点的指示符。括号里是切入点的表达式,可以配置切入增强的处理方法的特征,也支持模糊查询:
1.public * addNewUser(entity.User): * 表示匹配所有类型的返回值。
2.public void *(entity.User): * 表示匹配所有的方法名。
3.public void addNewUser(..): ".." 表示所有参数个数和类型。
4.* com.service.*.*(..): 这个表达式表示匹配com.service包下的所有类的所有方法。
5.* com.service..*.*(..): 这个表达式表示匹配com.service包以及其子包下所有类的所有方法。
<aop:aspect>标签引用包含增强方法的Bean,然后通过各种增强标签进行增强处理。
method:表示增强类中的某个方法。
pointcut-ref:引入增强的切入点。
----异常增强中的 throwing属性代表异常的参数名。
推荐阅读