AOP的理解和使用
1、理解
/** * 一、AOP的意思 * AOP的意思(aspect oriented programming)面向切面编程 * OOP的意思(Object oriented programming)面向对象编程 * OOA(Object Oriented Analysis):⾯向对象的分析 * OOD(Object Oriented Design):⾯向对象的设计 * * 二、AOP的作用 * 解偶 * * 三、定义 * * 基于OOP基础之上新的编程思想,指在程序运行期间、将某段代码动态的切入到指定方法的指定位置进行运行的这种编程方式叫面向切面编程。 * * 四、底层 * * 底层基于动态代理 * * 五、动态代理的优缺点 * * 1)优点:动态代理能实现结偶,能将某段代码动态的切入到指定方法的指定位置进行运行 * 2)缺点:写的麻烦、被代理类必须实现接口否则不能创建代理类。 * * */
2、动态代理的使用
public interface Calculator { public int add(int num,int num1); public int sub(int num,int num1); public int mul(int num,int num1); public int div(int num,int num1); } public class MyMathCalculator implements Calculator { @Override public int add(int num, int num1) { return num + num1; } @Override public int sub(int num, int num1) { return num - num1; } @Override public int mul(int num, int num1) { return num * num1; } @Override public int div(int num, int num1) { return num / num1; } } public class DynamicProxyFactory { //维护一个 被代理类 对象 用 Object 就可以了因为不知道 被代理类是那样的。 通过 构造器 初始化 属性 private static Object target; // 利用构造器对 代理对象 进行初始化 public DynamicProxyFactory(Object target) { this.target = target; } //给目标对象生成一个代理对象 /**三个参数的说明: * classLoder 代理类使用的类加载器和 被代理类使用的是一样的 加载器 * interfaces[] 和被代理类实现了共同的接口 * handler 调用处理器 实现了 InvocationHandler 这个接口的匿名实现类。重写方法 * 这个方法里面利用反射 调用 被代理类的方法。 * * */ //代理对象和被代理对象的关系 /** * * * * 代理类和被代理类 都实现了同一个接口,这个是他们俩能产生关联的唯一地方。 * * public static Object getProxyInstance() 这个是一个proxy类,和 被代理类不是同一个类型 * * 缺点:如果被代理类没有实现任何接口则没有办法创建被代理类 * */ public static Object getProxyInstance(){ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("JDK代理开始了"); System.out.println(method.getName()+"方法开始执行了参数是"+ Arrays.asList(args)); Object val = null; try{ val = method.invoke(target,args); }catch (Exception e){ System.out.println(method.getName()+"方法执行出现了异常"+ Arrays.asList(args)); } System.out.println(method.getName()+"方法执行完了结果是"+ val); return val; } }); } } @RequestMapping("/add") public void add(){ MyMathCalculator myMathCalculator = new MyMathCalculator(); DynamicProxyFactory dynamicProxyFactory = new DynamicProxyFactory(myMathCalculator); System.err.println(DynamicProxyFactory.getProxyInstance().getClass()); Calculator calculator = (Calculator)DynamicProxyFactory.getProxyInstance(); System.out.println(calculator.add(12,12)); System.err.println(calculator.sub(23,21)); System.out.println(calculator.div(12,0)); }
3、AOP使用的三种方法
aop的几个术语的理解
/**
*
* 横切关注点:就是一个具体的需求 比如说日志、安全
* 切面:就是一个类,日志的类
* 通知:就是切面类里面的某个方法
* 切入点: 某个类的某个方法。
* 切面类和和切入点所在的业务类都要放到容器里面
*
*/
3.1 使用spirng api 的方法
这样的虽然麻烦点 但是感觉可以获取的东西更多,我倾向于使用这个
<!-- AOP的方式一:使用原声spring API接口 --> <aop:config> <!-- 配置切入点 --> <aop:pointcut id="pointcut" expression="execution(* com.kuang.pojo.Car.runs())"/> <!--把Log 和 AfterLog 这个类切人到 方法上--> <aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:advisor> <aop:advisor advice-ref="logAfter" pointcut-ref="pointcut"/> </aop:config>
@Component public class Car { private String engine; public String runs(){ System.out.println("===== car ====="); return "gaohq"; } public String getEngine() { return engine; } public void setEngine(String engine) { this.engine = engine; } } @Component public class Log implements MethodBeforeAdvice { /* target 目标对象, 目标对象的目标方法将要执行 */ @Override public void before(Method method, Object[] args, @Nullable Object target) throws Throwable { System.out.println(target.getClass().getName()+"的"+method.getName()+"将要被执行"); } } @Component public class LogAfter implements AfterReturningAdvice { @Override public void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable { System.out.println(target.getClass().getName()+"的"+method.getName()+"执行完成,返回值是"+ returnValue); } } @RequestMapping("/h1") public String hello(){ car.runs(); return "name"; }
3.2 自定义类的方式
<!-- AOP的方式二:自定义类的方式 --> <aop:config> <aop:aspect ref="diyAop" > <aop:pointcut id="point" expression="execution(* com.kuang.pojo.Person.maintainCar())"/> <aop:before method="before" pointcut-ref="point" /> <aop:after method="after" pointcut-ref="point"/> </aop:aspect> </aop:config>
@Component public class DiyAop { public void before(){ System.out.println("方法执行前"); } public void after(){ System.out.println("方法执行后"); } } /** * 这里要注意调用maintainCar方法的时候不能 通过new对象的方式 * @return */ @RequestMapping("/person") public String person(){ car.setEngine("fengtian"); person.setCar(car); person.maintainCar(); return "name"; }
3.3 注解的方式
<!--方式 三:使用注解的方式,开启注解支持--> <aop:aspectj-autoproxy/>
/** * 需要放到容器里面 */ @Component @Aspect //标注这个类是个切面 public class AnotationPointCut { @Before("execution(* com.kuang.pojo.Red.red())") public void before(){ System.out.println("为什么呢?"); } @After("execution(* com.kuang.pojo.Red.red())") public void after(){ System.out.println("就是这么牛逼"); } @Around("execution(* com.kuang.pojo.Red.red())") public void arround(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println("环绕前"); Signature signature = joinPoint.getSignature();//获取签名 就是这个类的信息 System.out.println(signature); joinPoint.proceed(); System.out.println("环绕后"); } } @RequestMapping("/red") public String red(){ red.red(); return "name"; }