AOP概念
AOP说简单点就是将与业务不相关的代码进行分离,例如日志,权限,事务处理等。降低业务实现与不相关功能的耦合性,提高代码的重用性和易于维护,便是AOP所要做的事情。
Java代理机制
先不使用AOP,看看传统的Java代理机制,代码如下。
(1)编写一个日志信息的代理类,实现InvocationHandler接口
编写一个业务接口,并实现这个接口。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Created by jeysine on 2017/3/30.
*/
public class LogProxy implements InvocationHandler {
private Logger logger = Logger.getLogger(this.getClass().getName());
private Object delegate;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
try {
Long time = System.currentTimeMillis();
logger.log(Level.INFO, "开始执行方法");
result = method.invoke(delegate,args);
logger.log(Level.INFO, "执行方法结束");
time = System.currentTimeMillis() - time;
logger.log(Level.INFO, "耗时" + time + "毫秒");
}catch (Exception e){
logger.log(Level.INFO,e.toString());
}
return result;
}
public Object bind(Object delegate) {
this.delegate = delegate;
return Proxy.newProxyInstance(delegate.getClass().getClassLoader(),delegate.getClass().getInterfaces(),this);
}
}
(2)编写业务接口并实现该接口。
/**
* Created by jeysine on 2017/3/30.
*/
public interface BussinessInterface {
public void insert();
}
public class BussinessImpl implements BussinessInterface {
@Override
public void insert() {
for(int i = 0; i < 100000 ; i++){
//做一个耗时操作
}
System.out.println("执行insert方法");
}
}
(3)编写测试类。
/**
* Created by jeysine on 2017/3/30.
*/
public class TestMain {
public static void main(String[] args){
LogProxy logProxy = new LogProxy();
BussinessInterface bussinessInterface = (BussinessInterface) logProxy.bind(new BussinessImpl());
bussinessInterface.insert();
}
}
(4)测试结果。
执行insert方法
三月 30, 2017 2:07:13 下午 com.jeysine.weishop.test.LogProxy invoke
信息: 开始执行方法
三月 30, 2017 2:07:13 下午 com.jeysine.weishop.test.LogProxy invoke
信息: 执行方法结束
三月 30, 2017 2:07:13 下午 com.jeysine.weishop.test.LogProxy invoke
信息: 耗时117毫秒
AOP的自动代理
接下来使用AOP来实现该功能。
(1)先写个Before通知,也就是在切点之前执行的类,实现MethodBeforeAdvice接口代码如下:
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Created by jeysine on 2017/3/30.
*/
public class LogBefore implements MethodBeforeAdvice {
private Logger logger = Logger.getLogger(this.getClass().getName());
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
logger.log(Level.INFO, "开始执行方法");
}
}
(2)再写个After通知,在切点运行之后执行,实现AfterReturningAdvice接口,代码如下:
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Created by jeysine on 2017/3/30.
*/
public class LogAfter implements AfterReturningAdvice {
private Logger logger = Logger.getLogger(this.getClass().getName());
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
logger.log(Level.INFO,"执行方法结束");
}
}
(3)业务接口和实现类与前面的例子相同,就是BussinessInterface和BussinessImpl。
(4)配置Spring的AOP
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--配置业务类-->
<bean id="bussiness" class="com.jeysine.weishop.test.BussinessImpl" />
<!--配置before通知-->
<bean id="logBefore" class="com.jeysine.weishop.test.LogBefore" />
<bean id="logBeforeAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="logBefore"/>
<property name="patterns">
<!--采用正则表达式,如下是对所有方法进行-->
<value>.*.*</value>
</property>
</bean>
<!--配置after通知-->
<bean id="logAfter" class="com.jeysine.weishop.test.LogAfter" />
<bean id="logAfterAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="logAfter"/>
<property name="patterns">
<!--采用正则表达式,如下是对所有方法进行-->
<value>.*.*</value>
</property>
</bean>
</beans>
(5)编写测试类
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
/**
* Created by jeysine on 2017/3/30.
*/
public class TestMain {
public static void main(String[] args){
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:config.xml");
BussinessInterface bussinessInterface = (BussinessInterface)applicationContext.getBean("bussiness");
bussinessInterface.insert();
}
}
(6)运行结果如下:
15:12:28.562 [main] INFO o.s.b.f.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [config.xml]
执行insert方法
三月 30, 2017 3:12:28 下午 com.jeysine.weishop.test.LogBefore before
信息: 开始执行方法
三月 30, 2017 3:12:28 下午 com.jeysine.weishop.test.LogAfter afterReturning
信息: 执行方法结束