知识目标:
1)理解AOP的基本概念以及原理
2)熟悉AOP的相关基本术语
3)了解AOP的相关实现者
技能目标:
利用Spring注解和XML文件配置的方式实现AOP功能
本章设计模式要点:代理模式
使用方式:
public class client {
public static void main(String[] args) {
Subject sub = new RealSubject();
sub.visit();
}
}
何时使用:想在访问一个类时做一些访问控制
如何解决:增加中间层
应用实例:1)window的快捷方式 2)Spring AOP
优点:1)职责清晰2)高扩展性3)智能化
缺点:1)由于在客户端和真是主题之间增加了代理对象,
因此有些类型的代理模式可能会造成请求的处理速度变慢。
2)实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
从图中可以看出代理类与真正的实现类都是继承抽象的主题类,这样的好
处在于代理类可以与实际的类有相同的方法,可以保证客户端的使用透明性
一、AOP的基本概念
1)AOP的简介
1)基本概念:AOP即Aspect-Oriented Programming的缩写,中文名意识是面向切面(或方面)编程。它是一种思想,可在不改变程序源码的情况下为程序添加额外的功能
2)发展阶段:
静态AOP:Aspect形式,通过特定的编译器,将实现后的Aspect编译并织入到系统的静态类中
动态AOP:AOP的织入过程在系统运行开始之后进行,而不是预先编译到系统中
3)主要意图:允许通过分离应用的业务逻辑与系统服务进行内聚性的开发。应用对象只实现业务逻辑即可,并不负责其它的系统级关注点
4)应用场景:日志记录、程序跟踪、监控和优化,性能统计,安全、权限控制,应用系统的异常捕捉及处理,事务处理,缓存,持久化,懒加载(Lazy loading),内容传递,调试,资源池,同步等等
2)AOP的示例
transManager.beginTransaction();//事务开始
//业务逻辑
transManager.commit();//事务提交
横切的逻辑就是可以看作树的年轮,有三层年轮,最里面的那层代表的是业务逻辑,包裹业务层的是事务管理逻辑,最外面那层就是性能监视逻辑
传统的代码就是在业务代码中添加一大堆重复性的横切逻辑,日志输出、性能监视等,如果项目业务变得越来越复杂,那么代码也会变得越来越复杂,不够清晰,给维护带来巨大的困难
3)AOP的术语
连接点:程序某个特定位置,比如类初始化前,初始化后,方法调用前,方法调用后等
切点:通过切点来定位特定的连接点
增强:织入到目标类连接点上的一段程序代码
目标对象:增强的织入目标类
引介:引介是一种特殊的增强,它为类添加一些属性和方法
织入:将增强添加对目标类的具体连接点上的过程
代理:一个类被AOP织入增强后,会产生一个结果类,该类融合了原类和增强逻辑的代理类
切面:由切点和增强组成,既包括了横切逻辑的定义,也包括了连接点的定义
织入方法:编译器织入、类加载器织入、动态代理织入
4)AOP的实现者
AspectJ:AspectJ是目前最完善的AOP语言,对Java编程语言的进行了扩展,定义了AOP语法,能够在编译期提供横切代码的织入。AspectJ提供了两种横切实现机制,一种称为动态横切(Dynamic Crosscutting),另一种称为静态横切(Static Crosscutting)。
AspectWerkz:基于Java的简单、动态和轻量级的AOP框架,支持运行期或类装载期织入横切代码,它拥有一个特殊的类装载器。它与AspectJ项目已经合并,第一个发布版本是AspectJ5:扩展AspectJ语言,以基于注解的方式支持类似AspectJ的代码风格。
JBoss AOP:JBoss是一个开源的符合J2EE规范的应用服务器,作为J2EE规范的补充,JBoss中引入了AOP框架,为普通Java类提供了J2EE服务,而无需遵循EJB规范。JBoss通过类载入时,使用Javassist对字节码操作实现动态AOP框架。
Spring AOP:Spring AOP使用纯Java实现,不需要专门的编译过程,不需要特殊的类装载器,它在运行期通过代理方式向目标类织入增强代码。Spring并不尝试提供最完整的AOP实现,主要侧重于提供一种和Spring IoC容器整合的AOP实现,以解决企业级开发中常见问题。
二、AOP的实现方法
Proxy实现AOP:
1、首先要创建接口
package aop.proxy;
interface IUserInterface {
public void print();
}
2、创建实现接口的实现类
package aop.proxy;
public class UserBean implements IUserInterface{
private String name;
public UserBean() {}
public UserBean(String name){
this.name = name;
}
public <T> void println(T data){
System.out.println(data);
}
@Override
public void print() {
println("输出用户名字:"+this.name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
3、通过工厂模式创建代理类
package aop.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyFactory implements InvocationHandler {
private Object obj;
/**
*
* @param obj 创建目标类的代理实例
* @return
*
* newProxyInstance的三个参数:第一个参数为目标类的类加载器,第二个
* 参数的为目标类的类实现接口,第三个参数为this就是调用InvocationHandler本身
*/
public Object createUserProxy(Object obj){
this.obj = obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
UserBean uBean = (UserBean)this.obj;
Object object = null;
if(uBean.getName() != null)
object = method.invoke(uBean, args);
else
System.out.println("");
return object;
}
}
4、Main,调用代理对象,隐藏真实对象
package aop.proxy;
public class Main {
public static void main(String[] args) {
//1、通过接口创建真实类的对象
IUserInterface realObj = new UserBean("Lee");
//2、创建代理工厂实例
ProxyFactory factory = new ProxyFactory();
//3、通过代理工厂创建代理类实例
IUserInterface proxyObj = (IUserInterface)factory.createUserProxy(realObj);
proxyObj.print();
}
}
知识点为学习过程中归纳整理的笔记,非原创,如有侵权请指出