Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 7491667

Browse files
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)

AltStyle によって変換されたページ (->オリジナル) /