上一篇我们学习了IOC和AOP的基本概念,现在我们来深入了解一下。
IOC扩展
上一篇中使用Spring通过 setter访问器实现了对属性的赋值,这种做法称为设值注入。除此之外,Spring还提供了通过多种方式实现依赖注入。
构造注入(通过构造函数注入数据)
通过构造方法的赋值能力,称为构造注入。
示例:
类:
package cn.bdqn.spring.IOC;
public class HelloSpring {
public HelloSpring(){
System.out.println("调用无参构造方法");
}
public HelloSpring(String who,String hello){
System.out.println("调用带参构造方法");
this.who=who;
this.hello=hello;
}
//定义一个who属性,该属性的值通过Spring框架进行设置
private String who;
private String hello;
public void print(){
System.out.println(this.hello+this.who+"!");
}
}
配置文件
<!--使用构造注入-->
<bean id="HelloSpring" class="cn.bdqn.spring.IOC.HelloSpring">
<constructor-arg index="0" type="java.lang.String" value="Spring"/>
<constructor-arg index="1" type="java.lang.String" value="Heelo"/>
</bean>
解析
(1) 一个<constructor-arg>
元素表示构造方法的一个参数,且使用时不区分顺序。
(2)有多个参数通过<constructor-arg>
元素的index 属性可以指定该参数的位置索引,位置从0 开始。
(3)<constructor-arg>
元素还提供了type 属性用来指定参数的类型,避免字符串和基本数据类型的混淆。
构造注入的时效性较好,在对象实例化时就得到所依赖的对象,便于在构造函数中(初始化对象的过程中)使用所依赖的对象,但是灵活性不足。设值注入的方式较灵活,但时效性不足,并且大量属性的setter方法增加了类的复杂性。Spring并不倾向或提倡哪种注入方式,大家根据应用场景灵活选择。
p命名空间实现属性注入
非常简单:导入P的命名空间xmlns:p=“http://www.springframework.org/schema/p”
P命名空间的特点是使用元素的属性而非子节点的形式配置Bean的属性,从而简化配置
<bean id="HelloSpring" class="cn.bdqn.spring.IOC.HelloSpring" p:who="Spring" p:hello="Hello"/>
语法详讲:
对于一个类中的普通类型字段,比如String、int什么的,我们可以直接p:属性名="值"的方式进行赋值,这样就不用写子元素了,大大简化了配置。对于复杂类型,比如引用了其他的实体类(Bean组件),通过p:属性名-ref="所引用Bean的id"的方式进行赋值。
构造注入和设值注入对比
注入不同参数
在使用IOC时有时要注入一些特别的数据该怎么办
带有特殊符号的值
属性值中包含了XML中的特殊字符(&、<、>等),则注入时需要进行处理。可使用<![CDATA[特殊符号]]>进行标记,也可将特殊字符进行转义引用。
XML预定的实体引用:
符号 | 实体引用 |
---|---|
< | < |
> | > |
$ | & |
’ | ' |
" | " |
在这里发现CSDN中这些实体引用代表的也是这些特殊符号,逼的我不得不用代码形式标记起来。
注入集合类型的属性
非常简单,注入什么类型使用什么标签:
<property name="list">
<list>
<value>1</value>
<value>2</value>
</list>
</property>
<property name="set">
<set>
<value>1</value>
<value>2</value>
<value>3</value>
</set>
</property>
<property name="map">
<map>
<entry key="k1" value="v1"/>
<entry key="k2" value="v2"/>
</map>
</property>
注入null和空字符串值
注入null:
<property name="who">
<null/>
</property>
注入空字符串:
<property name="who" value=""/>
或
<property name="who" >
<value></value>
</property>
AOP扩展
环绕增强
将前置、后置、最终、异常这些增强结合到一起使用,还能控制返回值参数等,甚至控制目标方法是否执行。
增强类
//环绕增强:最强增强、控制方法是否运行,控制方法返回值、参数
public Object around(ProceedingJoinPoint pjp){
Object result=null;
try{
System.out.println("前置增强");
Object[] args=pjp.getArgs();//获得参数
args[0]="wsj";//设置参数
result = pjp.proceed(args);//执行目标方法并获得返回值
System.out.println("后置增强");
}catch (Throwable e){
System.out.println("异常增强");
}finally {
System.out.println("最终增强");
}
return result;//控制返回值
}
配置文件
<aop:config>
<!--切入点-->
<!--告诉Spring在哪切入 expression(连接点)告诉Spring连接谁-->
<aop:pointcut id="pc" expression="execution(public int addUser(..))"/>
<!--切面,告诉Spring增强谁(织入增强处理)-->
<aop:aspect ref="UserServiceLog">
<!-- <!–前置增强,method告诉Spring前置增强的方法是哪个,pointcut-ref引入切入点,告诉Spring切入谁(增强谁)–>
<aop:before method="before" pointcut-ref="pc"></aop:before>
<!–returning注入目标方法的返回值–>
<aop:after-returning method="afterReturning" pointcut-ref="pc" returning="result"></aop:after-returning>
<aop:after method="after" pointcut-ref="pc"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="pc" throwing="e"/>-->
<aop:around method="around" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>