AOP概述
什么是AOP
全称是Aspect Oriented Programming即:面向切面编程
在软件业:Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生泛型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重复性,同事提高了开发的效率
简单的书它就是把我们重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。
AOP的作用及优势
作用:
在程序远行期间,不修改源码对已有方法进行增强
优势:
- 减小重复代码
- 提高开发效率
- 维护方便
AOP的实现技术
使用动态代理技术
AOP具体应用
需求: 完成账户的增删改
以增加用户为例,在操作增加前,需要校验权限,操作增加后,需要进行日志记录
1,service
public class Demo01ServiceImpl implements Demo01Service {
@Override
public void addUser() {
System.out.println("Demo01ServiceImpl addUser");
}
@Override
public void updateUser() {
System.out.println("Demo01ServiceImpl updateUser");
}
@Override
public void deleteUser() {
System.out.println("Demo01ServiceImpl deleterUser");
}
}
2,dao层
public class UserDaoImpl implements UserDao {
@Override
public void addUser() {
System.out.println("User addUser");
}
@Override
public void updateUser() {
System.out.println("User updateUser");
}
@Override
public void deleteUser() {
System.out.println("User deleteUser");
}
}
存在问题
上面的代码,通过对业务层改造,已经可以实现在操作增加前,进行校验权限,操作增加后,进行日志记录,也产生了一个新的问题:业务层方法变得臃肿了,里面充斥着很多重复代码。
动态代理
- 字节码随用随创建,随用随加载
- 动态代理两种方式
1,JDK官方的Proxy类
基于接口的动态代理技术
被代理类最少实现一个接口
2,第三方的CGLib
基于父类的动态代理技术
如果包asmxxxx异常,余姚导入asm.jar
被代理类不能用final修饰类
动态代理之Proxy类
1,JDK官方的Proxy类
使用Proxy类改造getBean方法
public class MyApplicationContext {
private ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();
private String xmlPath;
public MyApplicationContext() {
}
public MyApplicationContext(String xmlPath) {
this.xmlPath = xmlPath;
parseXML(xmlPath);
}
/**
* 解析xml
*
* @param xmlPath
*/
private void parseXML(String xmlPath) {
SAXReader saxReader = new SAXReader();
InputStream inputStream = MyApplicationContext.class.getClassLoader().getResourceAsStream(xmlPath);
try {
Document document = saxReader.read(inputStream);
Element rootElement = document.getRootElement();
List<Element> elements = rootElement.elements();
elements.forEach(beanEle -> {
String id = beanEle.attributeValue("id");
String className = beanEle.attributeValue("class");
try {
Object instance = Class.forName(className).newInstance();
map.put(id, instance);
} catch (Exception e) {
e.printStackTrace();
}
});
} catch (DocumentException e) {
e.printStackTrace();
}
}
// 动态代理:1,JDK自带的Proxy 2,spring自带的Enhancer(cglib)
// JDk自带的proxy还是基于接口来进行方法增强!!!
public Object getBean(String id) {
// 普通实例:UserService / UserDao
Object object = map.get(id);
if (id.endsWith("Service")) {
// ClassLoader:被代理类的类加载器
// Class:被代理类的所实现的所有接口
// InvocationHandler:MyInvocationHandler实例
object = Proxy.newProxyInstance(object.getClass().getClassLoader(),
object.getClass().getInterfaces(),
new MyInvocationHandler((UserService) object));
}
return object;
}
}
MyInvocationHandler:
public class MyInvocationHandler implements InvocationHandler {
// 生命一个被代理类(被增强类)的引用
private UserService userService;
public MyInvocationHandler(UserService userService) {
this.userService = userService;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// System.out.println(proxy);
// Method method: 被代理类的方法
// Object[] args: 被代理类的方法的实际参数
// Object: 被代理类的方法的执行结果
String methodName = method.getName();
Object returnValue = null;
if ("addUser".equals(methodName) || "updateUser".equals(methodName)) {
System.out.println("权限校验");
// 使用原方法,相当于所有的原方法窦增强了
returnValue = method.invoke(userService,args);
System.out.println("日志记录");
} else {
// 只对addUser、updateUser方法进行增强,其他方法只是普通执行不增强
returnValue = method.invoke(userService,args);
}
return returnValue;
}
}
动态代理在Enhancer类
CGLib 的 Enhancer 类
使用Enhancer类改造getBean方法
cglib属于spring-core.jar中的组件,所以需要导入spring环境
public class MyApplicationContext {
private ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();
private String xmlPath;
public MyApplicationContext() {
}
public MyApplicationContext(String xmlPath) {
this.xmlPath = xmlPath;
parseXML(xmlPath);
}
/**
* 解析xml
*
* @param xmlPath
*/
private void parseXML(String xmlPath) {
SAXReader saxReader = new SAXReader();
InputStream inputStream = MyApplicationContext.class.getClassLoader().getResourceAsStream(xmlPath);
try {
Document document = saxReader.read(inputStream);
Element rootElement = document.getRootElement();
List<Element> elements = rootElement.elements();
elements.forEach(beanEle -> {
String id = beanEle.attributeValue("id");
String className = beanEle.attributeValue("class");
try {
Object instance = Class.forName(className).newInstance();
map.put(id, instance);
} catch (Exception e) {
e.printStackTrace();
}
});
} catch (DocumentException e) {
e.printStackTrace();
}
}
public Object getBean(String id) {
// cglib是属于spring框架技术,core的jar包
// 不是基于接口
Object object = map.get(id);
if (id.endsWith("Service")) {
// type: 被代理类的运行时对象
// callback: 相当于InvocationHandler
Object enhanceObject = Enhancer.create(object.getClass(), new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] args) throws Throwable {
// Method method, 原方法
// Object[] args, 原方法的实际参数
String methodName = method.getName();
Object returnValue = null;
if ("addUser".equals(methodName) || "updateUser".equals(methodName)) {
System.out.println("权限效验");
returnValue = method.invoke(object, args);
System.out.println("日志记录");
} else {
returnValue = method.invoke(object, args);
}
return returnValue;
}
});
}
return object;
}
}