关于面向切面编程(Spring AOP),是在java面试中经常提及的,只有在充分理解了,日常工作中才能得心应手。
如何理解AOP呢?首先我们要思考为什么要使用切面编程,如下图:
![b2e021f293837631eff9c5f8b41f288c.png](https://i-blog.csdnimg.cn/blog_migrate/6f217e515ad67568947ad5246f49ffdc.jpeg)
对于一个系统来说保存用户信息、权限分配的时候,我们会有数据库事务,保存要么同时成功,要么同时失败,用户信息、权限分配是面向对象设计的类对象,是横向的;数据库事
务是纵向的,像切面一样把他们切开。在编程中我们会发现:数据库的开闭,事务的管理是通用的,AOP可以抽取出来实现,简化我们的编程。
在Springboot中,javaBean是提供一个更强大的配置功能来增强JavaBean的功能,在java编程中,使用数据库时会写大量jdbc的try-catch代码,这个时候我们就能使用AOP编程将这些代码抽取出来,简化代码。
下面就用一个小实例初步理解面向切面编程(代码按照文末工程目录结构复制即可运行展示效果):
首先我们理解什么是动态代理模式:当你需要采访一名儿童的时候,首先你需要经过他的父母的同意,在一些问题上父母也许会替他回答,而对于另一些问题,也许父母觉得不太适合这个小孩会拒绝掉,这个时候小孩的父母就是他的代理(proxy)了。
动态代理的定义:生成一个占位,又称代理对象来代理目标对象,可以增强或者控制对孩子这个真实对象的访问。
1.约定编程,新建一个DinnerService接口
package com.springboot.chapter4.service;
/**
* @Auther:
* @Date: 2019/3/17 09:56
* @Description:
*/
public interface DinnerService {
public void eatDinner(String name);
}
再写一个DinnerService的实现类DinnerServiceImpl
package com.springboot.chapter4.service.impl;
import com.springboot.chapter4.service.DinnerService;
/**
* 描述:
*
* @author
* @create 2019-03-17 9:58
*/
public class DinnerServiceImpl implements DinnerService {
@Override
public void eatDinner(String name) {
if(name == null || name.trim() == ""){
throw new RuntimeException("parameter is null");
}
System.out.println("hello"+name);
}
}
2.在JDK中提供了类Proxy的静态方法newProxyInstance作为代理对象,我们让代理类EatProxy通过实现InvocationHandler接口来实现代理功能,代码如下:
package com.springboot.chapter4.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 描述:
*
* @author
* @create 2019-03-17 17:07
*/
public class EatProxy implements InvocationHandler {
// 引入目标对象:目的是吃晚餐
private Object target;
public static Object bind(Object target) {
EatProxy eatProxy = new EatProxy();
eatProxy.target = target;
Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
eatProxy);
return proxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("饭前洗手");
Object obj = method.invoke(target, args);
System.out.println("收拾饭菜");
System.out.println("收拾餐具");
return obj;
}
}
其中重写的invoke方法作为代理处理逻辑来处理业务
3.再写一个主函数AopMain
package com.springboot.chapter4.main;
import com.springboot.chapter4.proxy.EatProxy;
import com.springboot.chapter4.service.DinnerService;
import com.springboot.chapter4.service.impl.DinnerServiceImpl;
/**
* 描述:
*
* @author
* @create 2019-03-17 14:35
*/
public class AopMain {
public static void main(String[] args) {
DinnerService dinnerService = new DinnerServiceImpl();
DinnerService eatProxy = (DinnerService) EatProxy.bind(dinnerService);
eatProxy.eatDinner("晚饭好吃");
}
}
4.运行程序则可以看到”hello晚上吃饭“已经被调用,即我们第1步实现的接口代码已经被织入到约定的流程中。
![9a7dfa76dc5f1a7ed620693e497e5947.png](https://i-blog.csdnimg.cn/blog_migrate/b431ad78b95ff512457bb320f00069f0.jpeg)
项目工程截图如下:
![d197a3f9474c569519211e1cb0165ea8.png](https://i-blog.csdnimg.cn/blog_migrate/9357c8e0dccb2365682e439cece62cfe.jpeg)