什么是AOP
AOP(Aspect-OrientedProgramming,面向切面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。底层是通过Java的动态代理来实现,可以参考之前的文章 http://blog.csdn.net/shuaishuai123485615/article/details/52539798#t1 , 主要应用到比如:Spring AOP拦截器和持久层的事务等。
Spring AOP拦截器,当一个方法执行,Spring AOP 可以劫持一个执行的方法,在方法执行之前或之后添加额外的功能。
在Spring AOP中,有 4 种类型通知(advices)的支持:
-
通知(Advice)之前 - 该方法执行前运行
- 通知(Advice)返回之后 – 运行后,该方法返回一个结果
- 通知(Advice)抛出之后 – 运行方法抛出异常后,
- 环绕通知 – 环绕方法执行运行,结合以上这三个通知。
这里就举例第四种环绕通知,创建一个简单的客户服务类及一个print方法作为演示
package com.remote3c.bean;
public class CustomerService {
private String name;
private String url;
public void printName(){
System.out.println("Customer name "+ name);
}
public void printURL() {
System.out.println("Customer website : " + this.url);
}
public void printThrowException() {
throw new IllegalArgumentException();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
接着在创建一个实现了MethodInterceptor的类,必须调用“methodInvocation.proceed();” 继续在原来的方法执行,否则原来的方法将不会执行。
package com.remote3c.bean;
import java.util.Arrays;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class CustomerInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("Method name : "
+ methodInvocation.getMethod().getName());
System.out.println("Method arguments : "
+ Arrays.toString(methodInvocation.getArguments()));
// same with MethodBeforeAdvice
System.out.println("CustomerService: Before method CustomerService!");
try {
// proceed to original method call
Object result = methodInvocation.proceed();
// same with AfterReturningAdvice
System.out.println("CustomerService : Before after CustomerService!");
return result;
} catch (IllegalArgumentException e) {
// same with ThrowsAdvice
System.out.println("CustomerService : Throw exception CustomerService!");
throw e;
}
}
}
再然后在applicationContext.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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="helloPersion" class="com.remote3c.bean.Persion">
<property name="name" value="Yiibai" />
</bean>
<bean id="customerService" class="com.remote3c.bean.CustomerService">
<property name="name" value="my name is youshuai" />
<property name="url" value="http://www.remote3c.com" />
</bean>
<bean id="customerInterceptor" class="com.remote3c.bean.CustomerInterceptor"/>
<bean id="customerInterceptorProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="customerService" />
<property name="interceptorNames">
<list>
<value>customerInterceptor</value>
</list>
</property>
</bean>
</beans>
最后测试测试程序如下:
package com.remote3c.bean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Hello {
/**
* @author zhangyoushuai
* @date 2016-11-17
* @version 1.0.0
* @param args
* @throws IllegalAccessException
* @throws InstantiationException
*/
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
// TODO Auto-generated method stub
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
CustomerService obj = (CustomerService) context.getBean("customerInterceptorProxy");
System.out.println("****************");
obj.printName();
System.out.println("****************");
obj.printURL();
System.out.println("****************");
// obj.printThrowException();
}
输出结果:
****************
Method name : printName
Method arguments : []
CustomerService: Before method CustomerService!
Customer name my name is youshuai
CustomerService : Before after CustomerService!
****************
Method name : printURL
Method arguments : []
CustomerService: Before method CustomerService!
Customer website : http://www.remote3c.com
CustomerService : Before after CustomerService!
****************
这个Spring AOP通知的例子,一个类的整个方法被自动拦截。但在大多数情况下,可能只需要一种方式来拦截一个或两个方法,这就是为什么引入'切入点'的原因。它允许你通过它的方法名来拦截方法。另外,一个“切入点”必须具有“Advisor' 相关联。
在Spring AOP中,有三个非常专业术语- Advices, Pointcut, Advisor,把它在非官方的方式...
- Advice – 指示之前或方法执行后采取的行动。
- Pointcut– 指明哪些方法应该拦截,通过方法的名称或正则表达式模式。
- Advisor – 分组"通知"和”切入点“成为一个单元,并把它传递到代理工厂对象。
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="helloPersion" class="com.remote3c.bean.Persion">
<property name="name" value="Yiibai" />
</bean>
<bean id="customerService" class="com.remote3c.bean.CustomerService">
<property name="name" value="my name is youshuai" />
<property name="url" value="http://www.remote3c.com" />
</bean>
<bean id="customerInterceptor" class="com.remote3c.bean.CustomerInterceptor"/>
<bean id="customerInterceptorProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="customerService" />
<property name="interceptorNames">
<list>
<value>customerAdvisor</value>
</list>
</property>
</bean>
<bean id="customerYiibaicut" class="org.springframework.aop.support.NameMatchMethodPointcut">
<property name="mappedName" value="printName" />
</bean>
<bean id="customerAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut" ref="customerYiibaicut" />
<property name="advice" ref="customerInterceptor" />
</bean>
</beans>
运行结果如下:
****************
Method name : printName
Method arguments : []
CustomerService: Before method CustomerService!
Customer name my name is youshuai
CustomerService : Before after CustomerService!
****************
Customer website : http://www.remote3c.com
****************