通知包含了切面的逻辑,所以当创建一个通知对象时,即编写实现交叉功能的代码,而且Spring连接点模型建立在方法拦截上。这标识编写的Spring通知会在方法调用周围各个地方织入系统中。因为Spring可以在方法执行的多个地方织入通知,所以有多种通知类型。
前置通知(Before Advice):在目标执行之前被调用。对应接口BeforeAdvice
后置通知(After Returning Advice):在目标方法执行之后调用。对应接口AfterReturnAdvice
异常通知(After Throwing Advice):在目标方法抛出异常后调用。对应接口ThrowAdvice
环绕通知(Around Advice):在目标方法执行前后被调用。对应接口MethodInterceptor
引入通知(Introduction Advice):在目标类中添加一些新的方法和属性
前置通知(Before Advice)
java用法:
package test.advice;
public interface Reception {
public void serveCustomer(String customName);
}
package test.advice;
public class ConcreteReception implements Reception {
@Override
public void serveCustomer(String customName) {
// TODO Auto-generated method stub
System.out.println("我正在服务客户:" + customName);
}
}
package test.advice;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class GreetingBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
// TODO Auto-generated method stub
String customerName = (String) args[0];
System.out.println("欢迎:" + customerName + " ,很高兴为您服务");
}
}
package test.advice;
import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
public class Test {
public static void main(String[] args) {
Reception target = new ConcreteReception();
BeforeAdvice advice = new GreetingBeforeAdvice();
ProxyFactory pf = new ProxyFactory();
pf.setTarget(target);
pf.addAdvice(advice);
Reception proxy = (Reception) pf.getProxy();
proxy.serveCustomer("HeMaSoft.com");
}
}
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:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<bean id="greetingBeforeAdvice"
class="test.advice.GreetingBeforeAdvice">
</bean>
<bean id="reception"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"
value="test.advice.Reception"></property>
<property name="interceptorNames"
value="greetingBeforeAdvice">
</property>
<property name="target" ref="target"></property>
</bean>
<bean id="target" class="test.advice.ConcreteReception"></bean>
</beans>
package test.advice;
import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
// Reception target = new ConcreteReception();
// BeforeAdvice advice = new GreetingBeforeAdvice();
// ProxyFactory pf = new ProxyFactory();
// pf.setTarget(target);
// pf.addAdvice(advice);
// Reception proxy = (Reception) pf.getProxy();
// proxy.serveCustomer("HeMaSoft.com");
ApplicationContext context = new ClassPathXmlApplicationContext("spring-servlet.xml");
Reception reception = (Reception) context.getBean("reception");
reception.serveCustomer("Test");
}
}
ProxyFactoryBean是FactoryBean接口的实现类,负责为其他Bean创建代理实例,在内部使用ProxyFactory来完成这一工作。
target 代理目标的对象
proxyInterfaces 代理所有实现的接口,可以是多个接口。该属性还有一个别名属性interfaces
interceptorNames 需要织入目标对象的前置通知类数组(必须采用全限定类名),在内部interceptorNames是一个字符串数组,ProxyFactoryBean通过反射机制获取对应的类,他们可以是拦截器、通知或者包含通知的切入的advisor,配置中的顺序对应调用的顺序
singleton 返回的代理是否是单例,默认为单例
optimize 当设置为true时,强制使用CGLIB代理。对于其他作用域类型的代理,最好使用JDK代理。CGLIB创建代理的速度慢,而产生出的代理对象运行效率高,jdk代理相反
proxyTargetClass 是否对类惊醒代理,而不是对接口进行代理,设置为true时,使用CGLib代理。