Skip to content

Commit 7491667

Browse files
committed
Part 25: Add FirstAspect.java in myfirst-logging-spring-boot-starter module
1 parent 2d18b64 commit 7491667

File tree

1 file changed

+148
-0
lines changed
  • Spring_part_25/myfirst-logging-spring-boot-starter/src/main/java/spring/oldboy/logging/aop

1 file changed

+148
-0
lines changed
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
package spring.oldboy.logging.aop;
2+
3+
import org.aspectj.lang.annotation.Aspect;
4+
import org.aspectj.lang.annotation.Pointcut;
5+
6+
@Aspect
7+
public class FirstAspect {
8+
9+
/*
10+
@within - проверяем аннотации на уровне классов см. DOC/AOP_Articles/AOP_in_SpringBoot.txt,
11+
т.е. например, на нашем уровне контроллеров есть 3-и класса помеченных как @Controller, вот
12+
именно на них, после сканирования всего приложения произойдет срез и внедрение сквозной
13+
логики.
14+
15+
Еще раз, где в описании выражения есть знак '@' мы ищем аннотации для внедрения среза:
16+
@Controller, @Repository и т.д.
17+
*/
18+
@Pointcut("@within(org.springframework.stereotype.Controller)")
19+
public void isControllerLayer() {
20+
}
21+
22+
/*
23+
within - тут выражение БЕЗ знака '@', и мы уже проверяем имя класса, как всегда знак '*'
24+
означает что-то перед/после, например, User в UserService. Т.е. в данном примере нас
25+
интересуют все классы сервисного слоя, а они имеют названия заканчивающиеся на Service,
26+
см. spring/oldboy/service
27+
28+
Так же, если будут классы находиться в подкаталогах, то выражение станет (лишняя точка):
29+
"within(spring.oldboy.service..*Service)"
30+
31+
Естественно мы можем просто отдать в работу по срезу весь сервисный слой и тогда получим:
32+
"within(spring.oldboy.service.*)" или "within(spring.oldboy.service..*)"
33+
*/
34+
@Pointcut("within(spring.oldboy.service.*Service)")
35+
public void isServiceLayer() {
36+
}
37+
38+
/*
39+
В случае когда мы не можем задать условие по названию класса, или пакета, а тем более когда класс не аннотирован
40+
(классы слоя репозиториев необязательно аннотировать как @Repository), тем более, что это могут быть интерфейсы,
41+
а их реализация может лежать в другом месте приложения. В данном случае используют следующий синтаксис:
42+
43+
this - работает с AOP proxy классом;
44+
target - работает с целевым объектом, исходным объектом класса, который обернут в proxy;
45+
46+
В обоих предложенных вариантах (и target и this) мы ищем все классы реализующие интерфейс Repository -
47+
https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/Repository.html
48+
49+
@Pointcut("target(org.springframework.data.repository.Repository)")
50+
*/
51+
@Pointcut("this(org.springframework.data.repository.Repository)")
52+
public void isRepositoryLayer() {
53+
}
54+
55+
/*
56+
@annotation - мы снова видим знак '@', и тут, мы ищем УЖЕ аннотированные МЕТОДЫ, например, методы помеченные
57+
как @GetMapping в нашем случае. Тут есть неудобство - Spring будет сканировать все bean-ы. Мы можем ввести
58+
ограничения используя знаки логики '&&' - и, '||' - или, '!' - не.
59+
60+
В нашем случае мы знаем, что @GetMapping есть только на слое контроллеров. Вносим дополнительное условие -
61+
искать только среди контроллеров. И в данном случае произошло переиспользование одного pointcut-a в другом.
62+
*/
63+
@Pointcut("isControllerLayer() && @annotation(org.springframework.web.bind.annotation.GetMapping)")
64+
public void hasGetMapping() {
65+
}
66+
67+
/*
68+
Мы можем искать методы по наличию тех или иных (.. любых) параметров в методе, в нашем примере мы хотим
69+
найти только те методы, где параметр Model идет первым, далее при наличии ',' мы можем указать есть ли
70+
еще параметры в методе:
71+
72+
args - проверяем тип параметра метода, вариант с одним параметром - args(org.springframework.ui.Model) ;
73+
* - любой тип параметра, типы 2-ух из 3-х неизвестны - args(org.springframework.ui.Model,*,*) ;
74+
.. - 0 или любое количество параметров метода - args(org.springframework.ui.Model,..) ;
75+
76+
И снова можем применить дополнительную фильтрацию (условия) если знаем какой областью приложения хотим
77+
ограничить внедрение сквозной логики.
78+
*/
79+
@Pointcut("isControllerLayer() && args(org.springframework.ui.Model,..)")
80+
public void hasModelParam() {
81+
}
82+
83+
/*
84+
@args - в данном случае немного хитро, т.к. будут сканироваться аннотации над типом параметров методов, т.е.
85+
например у нас есть UserController:
86+
87+
public String create(@ModelAttribute
88+
@Validated ({Default.class, CreateAction.class})
89+
UserCreateEditDto userCreateEditDto,
90+
BindingResult bindingResult,
91+
RedirectAttributes redirectAttributes) {
92+
. . .
93+
}
94+
95+
В нем есть параметр класса (типа, type) UserCreateEditDto и вот именно его аннотации и будет сканировать @args,
96+
а не аннотации над самим параметром userCreateEditDto, именно над типом :
97+
98+
@Value
99+
@FieldNameConstants
100+
@UserInfo(groups = CreateAction.class)
101+
public class UserCreateEditDto {
102+
. . .
103+
}
104+
105+
Например, мы хотим проверять только аннотации @UserInfo у первого параметра методов.
106+
107+
Естественно в методе может быть масса параметров и их мы можем отметить, как:
108+
* - любой тип параметра ;
109+
.. - 0 или более параметров любого типа ;
110+
*/
111+
@Pointcut("isControllerLayer() && @args(spring.oldboy.validation.UserInfo,..)")
112+
public void hasUserInfoParamAnnotation() {
113+
}
114+
115+
/* bean - ищем bean-ы с конкретным именем, знак '*' тут работает, как и раньше */
116+
@Pointcut("bean(*Service)")
117+
public void isServiceLayerBean() {
118+
}
119+
120+
/*
121+
Lesson 118:
122+
123+
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
124+
125+
Наиболее часто используемое выражение для определения jointpoint. При использовании выражения execution возможно
126+
указывать пакет, имя класса, название метода, видимость метода, тип возвращаемого объекта и тип аргументов, см.
127+
DOC/AOP_Articles/AOP_in_SpringBoot.txt
128+
129+
Например:
130+
131+
- execution(String com.package.subpackage.Classname.someMethod(..)) - определяет вызов метода someMethod класса
132+
com.package.subpackage.Classname с любым количеством аргументов и возвращающий строку ;
133+
134+
- execution(* com.package.subpackage.Classname.*(..)) – вызов любого метода класса
135+
com.package.subpackage.Classname ;
136+
137+
- execution(* someMethod(..)) – вызов метода с именем someMethod у любого класса ;
138+
139+
В нашем пример мы ищем (вызываем): 'public' метод, возвращаемый методом тип нам не важен - '*', но можем указать
140+
и конкретно (Long, Integer и т.д.), далее указываем класс в котором может находиться метод -
141+
spring.oldboy.service.*Service, и наконец, через '.' мы прописываем метод с любым типом параметров, но можем и
142+
конкретизировать (Long, String и т.п.).
143+
*/
144+
145+
@Pointcut("execution(public * spring.oldboy.service.*Service.findById(*))")
146+
public void anyFindByIdServiceMethod() {
147+
}
148+
}

0 commit comments

Comments
 (0)