1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
|
== AspectJ 1.9.0
_© Copyright 2018 Contributors. All rights reserved._
The full list of resolved issues in 1.9.0 is available
https://bugs.eclipse.org/bugs/buglist.cgi?bug_status=RESOLVED&bug_status=VERIFIED&bug_status=CLOSED&f0=OP&f1=OP&f3=CP&f4=CP&j1=OR&list_id=16866879&product=AspectJ&query_format=advanced&target_milestone=1.9.0[here]
_Release info: 1.9.0 available 2-Apr-2018_
=== Improved runtime interface
New factory methods have been added to the AspectJ runtime. This is an
attempt to more optimally create `thisJoinPoint` and
`thisEnclosingJoinPoint` objects. The generated code that invokes these
now also uses the ability for the `LDC` bytecode instruction to load class
constants directly (this replaces what was happening previously where
generated code referenced string class names and class-loading was being
done from the AspectJ runtime as the woven application was starting).
This is turned on by using `-Xajruntimetarget:1.9`. This option was used
previously to enable users to target an old runtime if they knew that
old runtime is all that was available at some deployed target. The new
generation mechanism is not the default, not until it has had a bit more
testing out in the wild.
The changes to generated code have a couple of potential side effects:
* *overall size*: the woven code may be smaller due to the use of
smaller string constant pieces in the generated code (previously strings
were smashed together in the generated code and then taken apart by
AspectJ at runtime). Since the pieces are smaller, they can be shared
across other uses in the class file.
* *method size*: although the overall class may be smaller there are
more instructions involved in preparing the data for invocation of the
new joinpoint factory methods. It is possible if you have a lot of
joinpoints that we might blow the 64k instruction limit for the
`ajc$preClinit` method (where the factory invocation code is generated).
Please provide feedback if this happens to you!
In anticipation of not all build plugins supporting that
`-Xajruntimetarget` option, you can now specify these kinds of option in
the `ASPECTJ_OPTS` environment variable. Set that in your environment:
[source, text]
....
export ASPECTJ_OPTS="-Xajruntimetarget:1.9"
....
And it should get picked up by AspectJ when it runs.
== AspectJ 1.9.0.RC4
_Release info: 1.9.0.RC4 available 21-Feb-2018_
Primary changes in RC4 are to add support for `<compilerArg>` in the Ant
task. This enables users of the Ant task to pass in options supported by
the underlying AspectJ but not yet surfaced elsewhere. Particularly
useful with Java9 which includes a number of module related commands.
For example, here is an `iajc` usage with `compilerArg` that is passing
`--add-modules java.xml.bind`:
[source, xml]
....
<iajc destdir="bin" failonerror="true"
showWeaveInfo="true" source="1.9" target="1.9"
debug="true" fork="true" maxmem="256m">
<compilerArg value="--add-modules"/>
<compilerArg value="java.xml.bind"/>
<src path="src" />
<classpath>
<pathelement location="${aspectj.home}/lib/aspectjrt.jar"/>
</classpath>
</iajc>
....
== AspectJ 1.9.0.RC3
_Release info: 1.9.0.RC3 available 5-Feb-2018_
Primary changes in RC3 are to upgrade JDT and pickup all the fixes for
Java9 that have gone into it over the last few months.
== AspectJ 1.9.0.RC2
_Release info: 1.9.0.RC2 available 9-Nov-2017_
Key change in 1.9.0.RC2 is actually to be more tolerant of JDK10. The
version handling has been somewhat overhauled so AspectJ 9 will behave
better on Java 10 and future JDKs. This should put AspectJ in a better
place if new JDK versions are going to arrive thick and fast.
== AspectJ 1.9.0.RC1
_Release info: 1.9.0.RC1 available 20-Oct-2017_
This is the first release candidate of AspectJ 1.9.0 - the version of
AspectJ to be based on Java9. It includes a recent version of the
Eclipse Java9 compiler (from jdt core, commit #062ac5d7a6bf9).
=== Automatic Modules
AspectJ can now be used with the new module system available in Java9.
The key jars in AspectJ have been given automatic module names. The
automatic module name is `org.aspectj.runtime` for the `aspectjrt` module:
[source, text]
....
$ java --module-path <pathto>/lib/aspectjrt.jar --list-modules | grep aspectj
org.aspectj.runtime file:///<pathto>/lib/aspectjrt.jar automatic
....
And similarly `org.aspectj.weaver` and `org.aspectj.tools` for `aspectjweaver`
and `aspectjtools`, respectively:
[source, text]
....
$ java --module-path <pathto>/lib/aspectjweaver.jar --describe-module org.aspectj.weaver
org.aspectj.weaver file:///<pathto>/lib/aspectjweaver.jar automatic
requires java.base mandated
contains aj.org.objectweb.asm
contains aj.org.objectweb.asm.signature
contains org.aspectj.apache.bcel
contains org.aspectj.apache.bcel.classfile
contains org.aspectj.apache.bcel.classfile.annotation
contains org.aspectj.apache.bcel.generic
contains org.aspectj.apache.bcel.util
contains org.aspectj.asm
contains org.aspectj.asm.internal
...
....
=== Building woven modules
AspectJ understands `module-info.java` source files and building modules
that include aspects. Here is an example:
[source, java]
....
// module-info.java
module demo {
exports pkg;
requires org.aspectj.runtime;
}
// pkg/Demo.java
package pkg;
public class Demo {
public static void main(String[] argv) {
System.out.println("Demo running");
}
}
// otherpkg/Azpect.java
package otherpkg;
public aspect Azpect {
before(): execution(* *(..)) && !within(Azpect) {
System.out.println("Azpect running");
}
}
....
We can now build those into a module:
[source, text]
....
$ ajc -1.9 module-info.java otherpkg/Azpect.java pkg/Demo.java -outjar demo.jar
...
module-info.java:3 [error] org.aspectj.runtime cannot be resolved to a module
...
....
Wait, that failed! Yes, `aspectjrt.jar` (which includes the required
`org.aspectj.weaver` module) wasn't supplied. We need to pass it on the
module-path:
[source, text]
....
$ ajc -1.9 --module-path <pathto>/aspectjrt.jar module-info.java otherpkg/Azpect.java pkg/Demo.java -outjar demo.jar
....
Now we have a demo module we can run:
[source, text]
....
$ java --module-path <pathto>/aspectjrt.jar:demo.jar --module demo/pkg.Demo
Azpect running
Demo running
....
That's it!
=== Binary weaving with modules
A module is really just a jar with a _module-info_ descriptor. As such, you
can simply pass a module on the _inpath_ and binary-weave it with other
aspects. Take the module we built above, let's weave into it again:
[source, java]
....
// extra/AnotherAzpect.java
package extra;
public aspect AnotherAzpect {
before(): execution(* *(..)) && !within(*Azpect) {
System.out.println("AnotherAzpect running");
}
}
....
[source, text]
....
$ ajc -inpath demo.jar AnotherAzpect.java -outjar newdemo.jar
....
Notice how there was no complaint here that the `org.aspectj.runtime`
module hadn't been passed in. That is because inpath was being used
which doesn't treat specified jars as modules (and so does not check
dependencies). There is no _module-inpath_ right now.
Because the new JAR produced includes the compiled aspect, the
_module-info_ specification inside is still correct, so we can run it
exactly as before:
[source, text]
....
$ java --module-path ~/installs/aspectj190rc1/lib/aspectjrt.jar:newdemo.jar --module demo/pkg.Demo
Azpect running
AnotherAzpect running
Demo running
....
=== Faster Spring AOP
Dave Syer recently created a https://github.com/dsyer/spring-boot-aspectj[series of benchmarks] for checking the speed
of Spring-AspectJ.
Here we can see the numbers for AspectJ 1.8.11 (on an older Macbook
Pro):
[source, text]
....
Benchmark (scale) Mode Cnt Score Error Units
StartupBenchmark.ltw N/A avgt 10 2.553 ~ 0.030 s/op
StartupBenchmark.ltw_100 N/A avgt 10 2.608 ~ 0.046 s/op
StartupBenchmark.spring v0_10 avgt 10 2.120 ~ 0.148 s/op
StartupBenchmark.spring v1_10 avgt 10 2.219 ~ 0.066 s/op
StartupBenchmark.spring v1_100 avgt 10 2.244 ~ 0.030 s/op
StartupBenchmark.spring v10_50 avgt 10 2.950 ~ 0.026 s/op
StartupBenchmark.spring v20_50 avgt 10 3.854 ~ 0.090 s/op
StartupBenchmark.spring v20_100 avgt 10 4.003 ~ 0.038 s/op
StartupBenchmark.spring a0_10 avgt 10 2.067 ~ 0.019 s/op
StartupBenchmark.spring a1_10 avgt 10 2.724 ~ 0.023 s/op
StartupBenchmark.spring a1_100 avgt 10 2.778 ~ 0.057 s/op
StartupBenchmark.spring a10_50 avgt 10 7.191 ~ 0.134 s/op
StartupBenchmark.spring a10_100 avgt 10 7.191 ~ 0.168 s/op
StartupBenchmark.spring a20_50 avgt 10 11.541 ~ 0.158 s/op
StartupBenchmark.spring a20_100 avgt 10 11.464 ~ 0.157 s/op
....
So this is the average startup of an app affected by aspects applying to
the beans involved. Where numbers are referenced the first is the number
of aspects/pointcuts and the second is the number of beans. The 'a'
indicates an annotation based pointcut vs a non-annotation based
pointcut ('v'). Notice things are much worse for annotation based
pointcuts. At 20 pointcuts and 50 beans the app is 9 seconds slower to
startup. +
In AspectJ 1.8.12 and 1.9.0.RC1 some work has been done here. The key
change is to recognize that the use of annotations with runtime
retention is much more likely than annotations with class level
retention. Retrieving annotations with class retention is costly because
we must open the bytes for the class file and dig around in there (vs
runtime retention which are immediately accessible by reflection on the
types). In 1.8.11 the actual type of the annotation involved in the
matching is ignored and the code will fetch *all* the annotations on the
type/method/field being matched against. So even if the match is looking
for a runtime retention annotation, we were doing the costly thing of
fetching any class retention annotations. In 1.8.12/1.9.0.RC1 we take
the type of the match annotation into account - allowing us to skip
opening the classfiles in many cases. There is also some deeper work on
activating caches that were not previously being used correctly but the
primary change is factoring in the annotation type.
What difference does that make? AspectJ 1.9.0.RC1:
[source, text]
....
Benchmark (scale) Mode Cnt Score Error Units
StartupBenchmark.ltw N/A avgt 10 2.568 ~ 0.035 s/op
StartupBenchmark.ltw_100 N/A avgt 10 2.622 ~ 0.075 s/op
StartupBenchmark.spring v0_10 avgt 10 2.096 ~ 0.054 s/op
StartupBenchmark.spring v1_10 avgt 10 2.206 ~ 0.031 s/op
StartupBenchmark.spring v1_100 avgt 10 2.252 ~ 0.025 s/op
StartupBenchmark.spring v10_50 avgt 10 2.979 ~ 0.071 s/op
StartupBenchmark.spring v20_50 avgt 10 3.851 ~ 0.058 s/op
StartupBenchmark.spring v20_100 avgt 10 4.000 ~ 0.046 s/op
StartupBenchmark.spring a0_10 avgt 10 2.071 ~ 0.026 s/op
StartupBenchmark.spring a1_10 avgt 10 2.182 ~ 0.032 s/op
StartupBenchmark.spring a1_100 avgt 10 2.272 ~ 0.024 s/op
StartupBenchmark.spring a10_50 avgt 10 2.557 ~ 0.027 s/op
StartupBenchmark.spring a10_100 avgt 10 2.598 ~ 0.040 s/op
StartupBenchmark.spring a20_50 avgt 10 2.961 ~ 0.043 s/op
StartupBenchmark.spring a20_100 avgt 10 3.093 ~ 0.098 s/op
....
Look at the a20_100 case - instead of impacting start time by 9 seconds,
it impacts it by 1 second.
=== More to come...
* Eclipse JDT Java 9 support is still being actively worked on and lots
of fixes will be coming through over the next few months and included in
AspectJ 1.9.X revisions.
* AspectJ does not currently modify `module-info.java` files. An aspect
from one module applying to code in another module clearly introduces a
dependency between those two modules. There is no reason - other than
time! - that this can't be done.
(https://bugs.eclipse.org/bugs/show_bug.cgi?id=526244[Issue 526244])
* Related to that AspectJ, on detection of aspects should be able to
automatically introduce the `requires org.aspectj.runtime` to the
_module-info_. (https://bugs.eclipse.org/bugs/show_bug.cgi?id=526242[Issue
526242])
* Module-aware variants of AspectJ paths: `--module-inpath`,
`--module-aspectpath`.
(https://bugs.eclipse.org/bugs/show_bug.cgi?id=526243[Issue 526243])
|