Skip to content

Commit 903bd3e

Browse files
committed
change log
1 parent 905e037 commit 903bd3e

1 file changed

Lines changed: 83 additions & 1 deletion

File tree

changelog.md

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,90 @@ helloWorldService.helloWorld();
148148

149149
# 第二部分:AOP及实现
150150

151+
AOP相关概念较多,我不会一一列举,但是会在每一步对概念做一点解释。
152+
153+
AOP分为配置(Pointcut,Advice),织入(Weave)两部分工作,当然还有一部分是将AOP整合到整个容器的生命周期中。
154+
151155
## 7.step7-使用JDK动态代理实现AOP织入
152156
git checkout step-7-method-interceptor-by-jdk-dynamic-proxy
157+
158+
织入(weave)相对简单,我们先从它开始。Spring AOP的织入点是`AopProxy`,它包含一个方法`Object getProxy()`来获取代理后的对象。
159+
160+
在Spring AOP中,我觉得最重要的两个角色,就是我们熟悉的`MethodInterceptor``MethodInvocation`(这两个角色都是AOP联盟的标准),它们分别对应AOP中两个基本角色:`Advice``Joinpoint`。Advice定义了在切点指定的逻辑,而Joinpoint则代表切点。
161+
162+
```java
163+
public interface MethodInterceptor extends Interceptor {
164+
165+
Object invoke(MethodInvocation invocation) throws Throwable;
166+
}
167+
```
168+
169+
Spring的AOP只支持方法级别的调用,所以其实在AopProxy里,我们只需要将MethodInterceptor放入对象的方法调用即可。
170+
171+
我们称被代理对象为`TargetSource`,而`AdvisedSupport`就是保存TargetSource和MethodInterceptor的元数据对象。这一步我们先实现一个基于JDK动态代理的`JdkDynamicAopProxy`,它可以对接口进行代理。于是我们就有了基本的织入功能。
172+
173+
```java
174+
@Test
175+
public void testInterceptor() throws Exception {
176+
// --------- helloWorldService without AOP
177+
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("tinyioc.xml");
178+
HelloWorldService helloWorldService = (HelloWorldService) applicationContext.getBean("helloWorldService");
179+
helloWorldService.helloWorld();
180+
181+
// --------- helloWorldService with AOP
182+
// 1. 设置被代理对象(Joinpoint)
183+
AdvisedSupport advisedSupport = new AdvisedSupport();
184+
TargetSource targetSource = new TargetSource(helloWorldService, HelloWorldServiceImpl.class,
185+
HelloWorldService.class);
186+
advisedSupport.setTargetSource(targetSource);
187+
188+
// 2. 设置拦截器(Advice)
189+
TimerInterceptor timerInterceptor = new TimerInterceptor();
190+
advisedSupport.setMethodInterceptor(timerInterceptor);
191+
192+
// 3. 创建代理(Proxy)
193+
JdkDynamicAopProxy jdkDynamicAopProxy = new JdkDynamicAopProxy(advisedSupport);
194+
HelloWorldService helloWorldServiceProxy = (HelloWorldService) jdkDynamicAopProxy.getProxy();
195+
196+
// 4. 基于AOP的调用
197+
helloWorldServiceProxy.helloWorld();
198+
199+
}
200+
```
201+
153202

203+
## 8.step8-使用AspectJ管理切面
204+
git checkout step-8-invite-pointcut-and-aspectj
205+
206+
完成了织入之后,我们要考虑另外一个问题:对什么类以及什么方法进行AOP?对于“在哪切”这一问题的定义,我们又叫做“Pointcut”。Spring中关于Pointcut包含两个角色:`ClassFilter``MethodMatcher`,分别是对类和方法做匹配。Pointcut有很多种定义方法,例如类名匹配、正则匹配等,但是应用比较广泛的应该是和`AspectJ`表达式的方式。
207+
208+
`AspectJ`是一个“对Java的AOP增强”。它最早是其实是一门语言,我们跟写Java代码一样写它,然后静态编译之后,就有了AOP的功能。下面是一段AspectJ代码:
209+
210+
```java
211+
aspect PointObserving {
212+
private Vector Point.observers = new Vector();
213+
214+
public static void addObserver(Point p, Screen s) {
215+
p.observers.add(s);
216+
}
217+
public static void removeObserver(Point p, Screen s) {
218+
p.observers.remove(s);
219+
}
220+
...
221+
}
222+
```
223+
224+
这种方式无疑太重了,为了AOP,还要适应一种语言?所以现在使用也不多,但是它的`Pointcut`表达式被Spring借鉴了过来。于是我们实现了一个`AspectJExpressionPointcut`
225+
226+
```java
227+
@Test
228+
public void testMethodInterceptor() throws Exception {
229+
String expression = "execution(* us.codecraft.tinyioc.*.*(..))";
230+
AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut();
231+
aspectJExpressionPointcut.setExpression(expression);
232+
boolean matches = aspectJExpressionPointcut.getMethodMatcher().matches(HelloWorldServiceImpl.class.getDeclaredMethod("helloWorld"),HelloWorldServiceImpl.class);
233+
Assert.assertTrue(matches);
234+
}
235+
```
154236

155-
## 8.step8-使用Aspectj管理切面
237+
## 9.

0 commit comments

Comments
 (0)