概述:今天主要讲解spring的注解使用和分散配置、AOP的介绍
一、spring的注解
简介:在 Spring 2.5中已经可以用注解的方式去驱动 Spring 的依赖注射了,@Autowired注解提供了更细致的控制与更好的适应性。Spring 2.5 也支持 JSR-250 中的一些注解,例如@Resource,@PostConstruct,以及@PreDestroy。
a) @Autowired注解配置第一种
Autowired可以对成员变量、方法和构造函数进行标注,来完成自动装配的工作。@Autowired的标注位置不同,它们都会在Spring在初始化这个bean时,自动装配这个属性。要使@Autowired能够工作,还需要在配置文件中加入以下
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
b) 开启所有的注解
首先加入命名空间和地址,引入context的上下文标签,再使用context:annotation-config标签
该配置可激活在类中探测到的各种注解,@Required @Autowired @PostConstruct @PreDestroy @Resource @EJB @PersistenceContext @WebServiceRef等等,
1 <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"
2 xsi:schemaLocation="http://www.springframework.org/schema/beans
3 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
4 http://www.springframework.org/schema/context
5 http://www.springframework.org/schema/context/spring-context-2.5.xsd">
6 <context:annotation-config />
7 beans>
二、分散配置
a) 引入外部bean来读取外部配置文件 这样在<value>${name}</value>可以使用这个占位符来注入值了
<!--第一种,引入外部bean来读取外部配置文件-->
<bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<!--引入单个文件-->
<property name="location">
<value>person.properties</value>
</property>
<!--引入多个文件-->
<property name="locations">
<list>
<value>person.properties</value>
</list>
</property>
</bean>
b) 使用spring自带的context工具来读取外部文件
首先需要引入spring的context的命名空间和连接地址 。然后使用
<context:property-placeholder location="person.properties"/>来引入文件
c) 定制编辑器后处理类
i. 在配置文件中配置
<bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<!-- key指向的是:需要转换的类 -->
<entry key="cn.csdn.service.Address">
<!-- value指向的是 实现的编辑器类 -->
<bean class="cn.csdn.editor.AddressEditor"/>
</entry>
</map>
</property>
</bean>
ii. 在java中首先需要继承PropertyEditorSupport这个类然后实现setAsText方法,代码如下
public class AddressEditor extends PropertyEditorSupport{
@Override
public void setAsText(String text) throws IllegalArgumentException {
// TODO Auto-generated method stub
//java实现转换
if(!"".equals(text)){
String args[] = text.split("\\.");
if(args.length>3){
Address address = new Address();
address.setProvince(args[0]);
address.setCity(args[1]);
address.setStreet(args[2]);
address.setZipCode(args[3]);
setValue(address);
}else{
this.setAsText(null);
}
}else{
this.setAsText(null);
}
}
三、AOP的介绍
概述: 1.切面(aspect):要实现的交叉功能,是系统模块化的一个切面或领域。如日志记录。
2.连接点:应用程序执行过程中插入切面的地点,可以是方法调用,异常抛出,或者要修改的
字段。
3.通知:切面的实际实现,他通知系统新的行为。如在日志通知包含了实
现日志功能的代码,如向日志文件写日志。通知在连接点插入到应用系统中。
4.切入点:定义了通知应该应用在哪些连接点,通知可以应用到AOP框架支持的任何连接点。
5.引入:为类添加新方法和属性。
6.目标对象:被通知的对象。既可以是你编写的类也可以是第三方类。
7.代理:将通知应用到目标对象后创建的对象,应用系统的其他部分不用为了支持代理对象而
改变。
8.织入:将切面应用到目标对象从而创建一个新代理对象的过程。织入发生在目标
对象生命周期的多个点上:
编译期:切面在目标对象编译时织入.这需要一个特殊的编译器.
类装载期:切面在目标对象被载入JVM时织入.这需要一个特殊的类载入器.
运行期:切面在应用系统运行时织入.
a) 环绕通知
在java类中实现MethodInterceptor接口
public class MyAroundAdvice implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
// TODO Auto-generated method stub
System.out.println("执行方法之前执行一些操作");
Object obj=methodInvocation.proceed();
System.out.println("执行方法之后执行一些操作");
return obj;
}
}
在配置文件中配置
<!--业务bean-->
<bean id="personServiceBean" class="cn.csdn.service.PersonServiceBean"/>
<!--环绕通知-->
<bean id="myAroundAdvice" class="cn.csdn.advice.MyAroundAdvice"/>
<!--代理的接口-->
<property name="proxyInterfaces">
<list>
<value>cn.csdn.service.PersonService</value>
</list>
</property>
<!--通知名称-->
<property name="interceptorNames">
<list>
<value>myThrowsAdvice</value>
</list>
</property>
<!--通知的对象-->
<property name="target">
<ref bean="personServiceBean"/>
</property>
b) 前置通知
public class MyBeforeAdvice implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
// TODO Auto-generated method stub
//第一个参数 方法对象
//第二个参数 方法参数
//第三个参数 目标对象
Object arg=null;
if(args.length>0){
arg=args[0];
}
System.out.println("方法名:"+method.getName()+"---方法第一个参数的值"+arg+"目标对象是:"+target.toString());
}
}
在配置文件中声明该通知并在通知名称中加入<value>myBeforeAdvice</value>
<!--前置通知声明-->
<bean id="myBeforeAdvice" class="cn.csdn.advice.MyBeforeAdvice"/>
c) 后置通知
public class MyAfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method arg1, Object[] arg2,
Object arg3) throws Throwable {
// TODO Auto-generated method stub
System.out.println("after---------------------方法的返回值是:"+returnValue);
}
}
配置文件中和前置通知类似
d) 异常通知
public class MyThrowsAdvice implements ThrowsAdvice {
//异常处理操作
public void afterThrowing(Throwable throwable){
System.out.println("exception----------------------------"+throwable.getMessage());
}
}
配置文件中与前置通知类似
e) 引入通知
i. 声明接口
//添加一个属性 记录最后一次修改的时间
public interface Auditable {
void setLastModifiedDate(Date lastModifiedDate);
Date getLastModifiedDate();
}
ii. 引入拦截器并实现声明的接口
public class AuditableBean extends DelegatingIntroductionInterceptor implements Auditable{
private Date lastModifiedDate;
@Override
public void setLastModifiedDate(Date lastModifiedDate) {
// TODO Auto-generated method stub
this.lastModifiedDate=lastModifiedDate;
}
@Override
public Date getLastModifiedDate() {
// TODO Auto-generated method stub
return this.lastModifiedDate;
}
}
iii. 在配置文件中配置
<!--引入通知声明-->
<bean id="auditableBean" class="cn.csdn.service.AuditableBean"/>
<!--代理的接口-->
<property name="proxyInterfaces">
<list>
<value>cn.csdn.service.PersonService</value>
<!--将引入通知加入-->
<value>cn.csdn.service.Auditable</value>
</list>
</property>
<!--通知名称-->
<property name="interceptorNames">
<list>
<value>myThrowsAdvice</value>
<value>myAroundAdvice</value>
<value>myBeforeAdvice</value>
<value>myAfterAdvice</value>
<!--加入通知名称-->
<value>auditableBean</value>
</list>
</property>