AOP是面向切面编程,区别于oop,面向对象,一个是横向的,一个是纵向。
主要解决代码分散和混乱的问题。
1.概念:
切面:实现AOP共有的类
通知:切面类中实现切面功能的方法
连接点:程序被通知的特定位置
切点:连接点的定义
代理:向目标应用通知而产生的对象
2.配置
AOP的实现的基本要求:通过接口创建目标的代理。
1。首先是配置文件,2。然后启动扫描器<context:component-scan>和启动AOP注解支持<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
3.之后再逻辑方法类上定义容器管理@Component(“名称”)若不写名称,则默认是类名首字母小写的名字。
3.定义切面类,
定义容器管理@Component和@Aspect//切面类
4.定义通知
通知可分为@before前置通知、@After后置通知、@AfterReturning返回通知、@AfterThrowing异常通知、@Around环绕通知。
前置通知:
在方法执行前执行,参数JoinPoint,代表连接点
可以得到参数列表和方法名
通过getNmae和 getAtgs,反回的是object[]类型
后置通知;在方法之后执行,同样可以获得参数列表和方法名
异常通知:
throwing=“接受异常对象规定参数”
环绕通知:
5.定义切点表达式
@通知类型注解(pointCut=“execution(修饰符的返回值类型 包名.类名.方法名(参数类型))”)
6.公共切点@Pioneertcut
之后再调用切点表达式的时候直接写:通知类型(“公共切点表达式的类名piontCut”)
接口=============================
package com.hanqi.test; import org.springframework.stereotype.Component; public interface I_jsq { double add(double a ,double b); double div(double a ,double b); }
实现类业务逻辑类=========
package com.hanqi.test; import org.springframework.stereotype.Component; @Component("my1")//容器管理 public class Myjsq implements I_jsq { //连接点 @Override public double add(double a, double b) { //前置通知的连接点 //日志记录 // System.out.println("日志:a = "+a+" ,b = "+b); System.out.println(a+"+"+b+"="+(a+b)); if(a < 0) { throw new RuntimeException("运行时异常"); } return(a+b); //后置通知的连接点 } //连接点 @Override public double div(double a, double b) { //日志记录 //System.out.println("日志:a = "+a+" ,b = "+b); //检查 // if(b==0) // { // System.out.println("b不能是0"); // return -1; // } // else // { System.out.println(a+"/"+b+"="+(a/b)); return (a/b); //} } }
切面类================
package com.hanqi.test; import java.util.Arrays; import java.util.List; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; //切面类 @Component//容器管理 @Aspect//切面类 @Order(1) public class LogAspect { //定义公共切点 @Pointcut("execution(* com.hanqi.test.I_jsq.*(..))") public void pointCut() { } //前置通知@Before @Before("pointCut()")//引用公共切点 public void beforeLog(JoinPoint jp)//通知 JoinPoint表示连接点 { //连接点的方法名 String ms = jp.getSignature().getName(); //连接点方法的参数 List<Object> ls = Arrays.asList(jp.getArgs()); System.out.println("前置日志,方法名 = "+ms+" 参数列表= "+ls); } //后置通知 @After("pointCut()") public void afterLog(JoinPoint jp) { //连接点的方法名 String ms = jp.getSignature().getName(); //连接点方法的参数列表 List<Object> ls = Arrays.asList(jp.getArgs()); System.out.println("后置日志,方法名 = "+ms+" 参数列表= "+ls); } //返回通知 //@AfterReturning(pointcut="execution(* com.hanqi.test.I_jsq.*(..))" ,returning="rtn") @AfterReturning(pointcut="pointCut()" ,returning="rtn") public void returningLog(double rtn) { //接收返回值 System.out.println("返回值="+rtn); } //异常通知 @AfterThrowing(pointcut="pointCut()" , throwing="msg") public void errorLog(Exception msg) { System.out.println("异常通知="+msg.getMessage()); } //环绕通知 @Around("pointCut()")//切点表达式,第一个*表示返回类型,第二个*表示方法名 public Object aroundLog(ProceedingJoinPoint pjp) { Object rtn= null; //连接点的方法名 String ms = pjp.getSignature().getName(); //连接点方法的参数 List<Object> ls = Arrays.asList(pjp.getArgs()); //实现四种通知 //1.前置通知 System.out.println("这是环绕通知的前置通知,方法名= "+ms+" 参数="+ls); //调用目标方法 try { rtn= pjp.proceed(); //3.返回通知 System.out.println("这是环绕通知的返回通知,返回值="+rtn ); } catch (Throwable e) { //4.异常通知 System.out.println("这是环绕通知的异常通知,异常信息="+e.getMessage()); e.printStackTrace(); } finally { //2.后置通知 System.out.println("这是环绕通知的后置通知"); } return rtn; } }
package com.hanqi.test; import java.util.Arrays; import java.util.List; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; // 切面类 @Component @Aspect @Order(2) public class CheckAspect { //前置通知 //@Before("execution(* com.hanqi.test.Myjsq.div(double,double))") @Before("LogAspect.pointCut()")//重用切点表达式 public void beforeCheck(JoinPoint jp) { //获取参数 Object[] ob = jp.getArgs(); if((Double.parseDouble(ob[1].toString()))== 0) { System.out.println("参数不能等于0"); System.out.println("1=="+Double.parseDouble(ob[1].toString())); System.out.println("0=="+Double.parseDouble(ob[0].toString())); } } }
测试类
package com.hanqi.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestMain { public static void main(String[] args) { // TODO 自动生成的方法存根 //I_jsq jsq1 = new Myjsq(); ApplicationContext ac = new ClassPathXmlApplicationContext("app.xml"); I_jsq jsq1 =(I_jsq)ac.getBean("my1");//通过接口创建代理对象 jsq1.add(123, 456); jsq1.div(200, 0); } }