什么是AOP?
AOP(Aspect-OrientedProgramming,面向方面编程)和OOP(Object-Oriented Programing,面向对象编程)思想不同,两者并非对立关系,前者是后者的补充,后者因为前者的补充而减少重复代码,使程序降低模块间的偶合度,增加未来代码的可操作性和可维护性。
为什么要用AOP模式?
如果我们在业务逻辑中需要对对象中的方法的调用进行记录统计等功能时,通常需要在每个类中新增一个方法来完成相应共能,如此以来代码中就会有很多重复的部分,程序也会高度偶合难以维护。
AOP主要功能:
主要功能:日志记录,性能统计,安全控制,事务处理,异常处理等等。AOP主要就是为了将这些功能从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码代码中。
下面我们简单的来看一下spring中如何实现AOP编程。
spring中实现AOP可以用注解和配置xml两种模式。
我们先来看一下使用注解方式如何实现。
首先我们需要一个接口,和实现它的类。
接口:
public interface PersonService { public String getPersonName(Integer id); public void save(String name); }
实现类:
public class PersonServiceBean implements PersonService { @Override public String getPersonName(Integer id) { // TODO Auto-generated method stub return null; } @Override public void save(String name) { // TODO Auto-generated method stub System.out.println("您输入的是" + name); } }
接着我们需要配置xml文件,需要把业务bean交给spring来管理
xml:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" 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-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <aop:aspectj-autoproxy proxy-target-class="true"/> <bean id="myInterceptor" class="cn.qdlg.service.MyInterceptor"></bean> <bean id="PersonService" class="cn.qdlg.service.impl.PersonServiceBean"></bean> </beans>
接下来我们需要完成拦截类定义切面和切入点
public class MyInterceptor { @Pointcut("execution (* cn.qdlg.service.impl.PersonServiceBean.*(..))") public void anyMethod(){} @Before("anyMethod()") public void doAccessCheck(String name){ System.out.println("前置通知" + name); } @AfterReturning("anyMethod() && args(name)") public void doAfterReturn(String result){ System.out.println("后置通知" + result); } @After("anyMethod()") public Object doAfter(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("进入方法"); Object result = pjp.proceed(); System.out.println("最终通知"); return result; } @AfterThrowing("anyMethod()") public void doAfterThrowing(Exception e){ System.out.println("例外通知" + e); } @Around("anyMethod()") public void doAround(){ System.out.println("环绕通知"); } }
最后我们可以写一个测试方法,调用被拦截类的方法。
如果是xml配置实现:
需要在配置文件中配置切面和切入点
在原有xml文件中加入以下代码
<aop:config> <aop:aspect id="asp" ref="myInterceptor"> <aop:pointcut id="mycut" expression="execution(* cn.qdlg.service.impl.PersonServiceBean.*(..))"/> <aop:before pointcut-ref="mycut" method="doAccessCheck"/> <aop:after pointcut-ref="mycut" method="doAfter"/> <aop:after-returning pointcut-ref="mycut" method="doAfterReturn"/> <aop:around pointcut-ref="mycut" method="doAround"/> <aop:after-throwing pointcut-ref="mycut" method="doAfterThrowing"/> </aop:aspect> </aop:config>
spring中实现AOP用的是JDK代理和CGLIB代理
JDK动态代理只针对实现了接口的类生成代理
CGlib代理针对类实现代理,主要是指定的类生成的一个子类,覆盖其中所有的方法,该类的方法不能声明为final
如果目标没有实现接口,则会默认采用cglib代理
我们来看一下JDK和CGLIB代理如何实现JDK代理
public class JDKProxyFactory implements InvocationHandler{ private Object targetobject; public Object creatProxyFactory(Object targetobject){ this.targetobject = targetobject; return Proxy.newProxyInstance(this.targetobject.getClass().getClassLoader(), this.targetobject.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { PersonServiceBean bean = (PersonServiceBean) this.targetobject; Object result = null; if(bean.getPersonName()!=null){ result = method.invoke(targetobject, args); } return result; } }
CGLIB代理
public class CGlibProxyFactory implements MethodInterceptor { public Object targetObject; public Object creatProxyIntance(Object targetObject){ this.targetObject = targetObject ; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.targetObject.getClass()); enhancer.setCallback(this); return enhancer.create(); } public Object intercept(Object proxy,Method method,Object[] args, MethodProxy methodproxy) throws Throwable{ PersonServiceBean bean = (PersonServiceBean) this.targetObject; Object result = null; if(bean.getPersonName()!=null){ result = methodproxy.invoke(targetObject, args); } return result; } }