AOP是Aspect Oriented Programming的缩写,意思是面向方面编程,一种新兴的编程技术。
AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,
AOP可以说也是这种目标的一种实现。它可以解决OOP和过程化方法不能够很好解决的横切
(crosscut)问题,
如:事务、安全、日志等横切关注。当未来系统变得越来越复杂,
横切关注点就成为一个大问题的时候,AOP就可以很轻松的解决横切关注点这个问题。
比如有这样一个情景:
Java代码
1.public class AccountManager {
2. private static final sysLogger = Instance();
3. private AuthorizationManager authMgr = new AuthorizationManager();
4.
5. public void transferFunds(String from, String to, int amount) {
6. sysLogger.log("transfer funds from " + from + " to " + to);
7. if(authMgr.accessAble(from) && authMgr.accessAble(to)) {
8. sysLogger.log("access successfully");
9. CustomerAccount from = findAccount(from);
10. CustomerAccount to = findAccount(to);
11. from.debit(amount);
12. to.credit(amount);
13. } else {
14. sysLogger.log("access deny");
15. }
16. sysLogger.log("transfer funds from " + from + " to " + to + " $" + amount + " successfully!");
17. }
18.}
public class AccountManager {
private static final sysLogger = Instance();
private AuthorizationManager authMgr = new AuthorizationManager();
public void transferFunds(String from, String to, int amount) {
sysLogger.log("transfer funds from " + from + " to " + to);
if(authMgr.accessAble(from) && authMgr.accessAble(to)) {
sysLogger.log("access successfully");
CustomerAccount from = findAccount(from);
CustomerAccount to = findAccount(to);
from.debit(amount);
} else {
sysLogger.log("access deny");
}
sysLogger.log("transfer funds from " + from + " to " + to + " $" + amount + " successfully!");
}
}
这个例子虽然是很好的面向对象代码,但是在业务处理逻辑中夹杂这日志处理和权限判断,变得复杂混乱.
在 AOP 中,正交关注点(如安全和日志记录)被识别为系统中的常见横切关注点。说它们是横切,
是因为它们总是切入模块(如包、类和代码文件)的多个单位。也许横切关注点可能不是核心业务逻辑的一部分,但是它们是应用程序的基本部分。
AOP的实现主要是通过方法的拦截实现.在不使用AOP框架的情况下,我们可以通过JDK提供的动态代理来实现方法的拦截
注意:使用JDK提供的动态代理实现
要求我们的目标对象必须实现接口
IUserBean接口
Java代码
1.hou.aop;
2.
3.public interface I
UserBean {
4.
5. public void getUser();
6.
7. public void addUser();
8.
9. public void updateUser();
10.
11. public void deleteUser();
12.}
hou.aop;
public interface IUserBean {
public void getUser();
public void addUser();
public void updateUser();
public void deleteUser();
}
IUserBean实现类 UserBean.java
Java代码
1.hou.aop;
2.
3.public class UserBean implements IUserBean {
4.
5. private String user = null;
6.
7. public UserBean() {
8. }
9.
10. public UserBean(String user) {
11. this.user = user;
12. }
13.
14. public void setUser(String user) {
15. this.user = user;
16. }
17.
18. public void addUser() {
19. System.out.println("this is addUser() method!");
20. }
21.
22. public void deleteUser() {
23. System.out.println("this is deleteUser() method!");
24. }
25.
26. public void getUser() {
27. System.out.println("this is getUser() method!");
28. }
29.
30. public void updateUser() {
31. System.out.println("this is updateUser() method!");
32. }
33.}
hou.aop;
public class UserBean implements IUserBean {
private String user = null;
public UserBean() {
}
public UserBean(String user) {
this.user = user;
}
public void setUser(String user) {
this.user = user;
}
public void addUser() {
System.out.println("this is addUser() method!");
}
public void deleteUser() {
System.out.println("this is deleteUser() method!");
}
public void getUser() {
System.out.println("this is getUser() method!");
}
public void updateUser() {
System.out.println("this is updateUser() method!");
}
}spring aop应用场景
我们希望在UserBean执行方法之前先检查userName是不是为空,以此做为权限判断.
当然我们可以在没个方法里面去加这些判断,但是这需要为每个方法都添加同样的判断,维护不便.
使用JDK提供的动态代理技术可以很方便的实现上面的需求:
通过flect.Proxy;提供的
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
方法可以生成一个动态代理对象
其中
loader是类装载器
interfaces是目标对象实现的一系列接口
h是一个实现InvocationHandler接口的类,我们对代理对象的所有操作都经过它处理
这样我们就可以拦截到UserBean的方法,在方法执行前先判断是否有权限,如果有则执行方法,
没有权限的话就不执行方法.
编写我们的代理类:
JDKProxy.java
Java代码
1.hou.aop;
2.
3.import flect.InvocationHandler;
4.import flect.Method;
5.import java.lan
6.
7.public class JDKProxy implements InvocationHandler {
8.
9. private Object targetObject;
10.
11. public Object createProxyObject(Object targetObject) {
12. this.targetObject = targetObject;
13. //生成代理对象
14. wProxyInstance(Class().getClassLoader(),Class().getInterfaces(),this);
15. }
16.
17. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
18. UserBean userBean = (UserBean) targetObject;
19. String userName = UserName();
20. Object result = null;
21. //权限判断
22. if(userName!=null && !"".equals(userName)) {
23. //调用目标对象的方法
24. result = method.invoke(targetObject, args);
25. }
26. return result;
27. }
28.}
hou.aop;
import flect.InvocationHandler;
import flect.Method;
import flect.Proxy;
public class JDKProxy implements InvocationHandler {
private Object targetObject;
public Object createProxyObject(Object targetObject) {
this.targetObject = targetObject;
//生成代理对象
wProxyInstance(Class().getClassLoader(),Class().getInterfaces(),this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
UserBean userBean = (UserBean) targetObject;
String userName = UserName();
Object result = null;
//权限判断
if(userName!=null && !"".equals(userName)) {
//调用目标对象的方法
result = method.invoke(targetObject, args);
}
return result;
}
}
通过调用createProxyObject可以生成代理对象,
编写测试类如下:
Java代码
1.hou.aop;
2.
3.public class TestProxy {
4.
5. public static void main(String[] args) {
6. JDKProxy jProxy = new JDKProxy();
7. IUserBean userBean = (IUserBean) ateProxyObject(new UserBean("royzhou"));
8. userBean.addUser();
9. }
10.}
hou.aop;
public class TestProxy {
public static void main(String[] args) {
JDKProxy jProxy = new JDKProxy();
IUserBean userBean = (IUserBean) ateProxyObject(new UserBean("royzhou"));
userBean.addUser();
}
}
执行成功后输出:
this is addUser() method!
再次修改测试类:
Java代码
1.hou.aop;
2.
3.public class TestProxy {
4.
5. public static void main(String[] args) {
6. JDKProxy jProxy = new JDKProxy();
7. IUserBean userBean = (IUserBean) ateProxyObject(new UserBean());
8. userBean.addUser();
9. }
10.}
hou.aop;
public cla
ss TestProxy {
public static void main(String[] args) {
JDKProxy jProxy = new JDKProxy();
IUserBean userBean = (IUserBean) ateProxyObject(new UserBean());
userBean.addUser();
}
}
即当用户没有权限时,控制台不输出东西,说明我们拦截方法对其做的权限判断生效了.
从上面这个例子可以成功拦截了调用的方法并对其做了相应的处理
如果不使用JDK提供的Proxy类
通过cglib创建代理类,好处是不要求我们的目标对象实现接口
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Class());
enhancer.setCallback(this); //回调,参数是一个实现MethodInterceptor接口的类,我们对代理对象的所有操作都经过它处理
ate(); //创建代理对象
修改UserBean 去掉IUserBean接口
Java代码
1.hou.aop;
2.
3.public class UserBean {
4.
5. private String userName = null;
6.
7. public UserBean() {
8. }
9.
10. public UserBean(String userName) {
11. this.userName = userName;
12. }
13.
14. public void addUser() {
15. System.out.println("this is addUser() method!");
16. }
17.
18. public void deleteUser() {
19. System.out.println("this is deleteUser() method!");
20. }
21.
22. public void getUser() {
23. System.out.println("this is getUser() method!");
24. }
25.
26. public void updateUser() {
27. System.out.println("this is updateUser() method!");
28. }
29.
30. public String getUserName() {
31. return userName;
32. }
33.
34. public void setUserName(String userName) {
35. this.userName = userName;
36. }
37.}
hou.aop;
public class UserBean {
private String userName = null;
public UserBean() {
}
public UserBean(String userName) {
this.userName = userName;
}
public void addUser() {
System.out.println("this is addUser() method!");
}
public void deleteUser() {
System.out.println("this is deleteUser() method!");
}
public void getUser() {
System.out.println("this is getUser() method!");
}
public void updateUser() {
System.out.println("this is updateUser() method!");
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
通过cglib创建代理类
CGLibProxy.java
Java代码
1.hou.aop;
2.
3.import flect.Method;
4.
5.import lib.proxy.Enhancer;
6.import lib.proxy.MethodInterceptor;
7.import lib.proxy.MethodProxy;
8.
9.public class CGLibProxy implements MethodInterceptor {
10.
11. private Object targetObject;
12.
13. public Object createProx
yObject(Object targetObject) {
14. this.targetObject = targetObject;
15. Enhancer enhancer = new Enhancer();
16. enhancer.setSuperclass(Class()); //非final 进行覆盖
17. enhancer.setCallback(this); //回调,通过
18. ate(); //创建代理对象
19. }
20.
21. public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
22. UserBean userBean = (UserBean) targetObject;
23. String userName = UserName();
24. Object result = null;
25. if(userName!=null && !"".equals(userName)) {
26. //调用目标对象的方法
27. result = methodProxy.invoke(targetObject, args);
28. }
29. return result;
30. }
31.}
hou.aop;
import flect.Method;
import lib.proxy.Enhancer;
import lib.proxy.MethodInterceptor;
import lib.proxy.MethodProxy;
public class CGLibProxy implements MethodInterceptor {
private Object targetObject;
public Object createProxyObject(Object targetObject) {
this.targetObject = targetObject;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Class()); //非final 进行覆盖
enhancer.setCallback(this); //回调,通过
ate(); //创建代理对象
}
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
UserBean userBean = (UserBean) targetObject;
String userName = UserName();
Object result = null;
if(userName!=null && !"".equals(userName)) {
//调用目标对象的方法
result = methodProxy.invoke(targetObject, args);
}
return result;
}
}
编写测试类:
Java代码
1.hou.aop;
2.
3.public class TestProxy {
4.
5. public static void main(String[] args) {
6. CGLibProxy cProxy = new CGLibProxy();
7. UserBean userBean = (UserBean) ateProxyObject(new UserBean("royzhou"));
8. userBean.addUser();
9. }
10.}
hou.aop;
public class TestProxy {
public static void main(String[] args) {
CGLibProxy cProxy = new CGLibProxy();
UserBean userBean = (UserBean) ateProxyObject(new UserBean("royzhou"));
userBean.addUser();
}
}
输出:
this is addUser() method!
当取消用户权限时,控制台不输出任何东西.
说明通过CGLib成功生成代理对象,拦截了目标对象的方法.
Spring主要通过代理来实现AOP
下面是AOP的一些基本概念:
切面(Aspect):对横切关注点的抽象(类似类对对象的抽象)
连接点(JoinPoint):被拦截到的点,泛指方法
切入点(CutPoint):对哪些连接点进行拦截的定义
通知(Advice):在特
定的连接点,AOP框架执行的动作.前置/后置/例外/最终/环绕通知(调用方法之前执行,全部执行完毕之后)
引入(Introduction): 添加方法或字段到被通知的类。 Spring允许引入新的接口到任何被通知的对象。例如,你可以使用一个引入使任何对象实现 IsModified接口,来简化缓存。
目标对象(Target Object): 包含连接点的对象。也被称作 被通知或被代理对象。
AOP代理(AOP Proxy): AOP框架创建的对象,包含通知。 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
织入(Weaving): 组装方面来创建一个被通知对象。这可以在编译时 完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样, 在运行时完成织入。
Adive通知可理解如下:
Java代码
1.public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
2. UserBean userBean = (UserBean) targetObject;
3. String userName = UserName();
4. Object result = null;
5. if(userName!=null && !"".equals(userName)) {
6. //调用目标对象的方法
7. try {
8. //前置通知
9. result = method.invoke(targetObject, args);
10. //后置通知
11. } catch(Exception e) {
12. //例外通知
13. } finally {
14. //最终通知
15. }
16. }
17. //环绕通知(前置通知之后,目标对象方法调用之前执行,全部执行完毕(最终通知)之后)
18. return result;
19. }
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
UserBean userBean = (UserBean) targetObject;
String userName = UserName();
Object result = null;
if(userName!=null && !"".equals(userName)) {
//调用目标对象的方法
try {
//前置通知
result = method.invoke(targetObject, args);
//后置通知
} catch(Exception e) {
//例外通知
} finally {
//最终通知
}
}
//环绕通知(前置通知之后,目标对象方法调用之前执行,全部执行完毕(最终通知)之后)
return result;
}
Spring提供两种方式实现AOP
一种是XML配置的方式
一种是annotation注解的方式
不管采用哪种方式,都必须在spring的配置文件中配置AOP支持:
Xml代码
1.<?xml version="1.0" encoding="UTF-8"?>
2.<beans xmlns="/schema/beans"
3. xmlns:xsi="/2001/XMLSchema-instance"
4. xmlns:context="/schema/context"
5. xmlns:aop="/schema/aop"
6. xsi:schemaLocation="/schema/beans
7. htt
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论