Резюме
Семейная корзина Spring помогает веб-разработчикам Java сэкономить много времени на разработке и повысить эффективность. Однако, поскольку многие детали скрыты, многие разработчики только знают об этом и не знают, почему.Эта статья предназначена для анализа некоторых аннотаций с использованием Spring, которые не могут быть вызваны сами по себе. Так как таких статей много, некоторые места не будут подробно описаны, а другие статьи будут цитироваться напрямую.
проблема
- Какие аннотации в Spring нельзя использовать для самовызова
- Почему прокси не может позвонить сам?
- Обычно используется весной
@Cache
,@Async
,@Transaction
В чем разница между этими тремя принципами? - Как решить проблему самовызова
- Каковы подводные камни использования разных решений?
Обзор АОП
В первую очередь необходимо уточнить несколько существительных, которые необходимо различатьAOP
Spring AOP
AspectJ
AOP
Аспектно-ориентированное программирование, аспектно-ориентированное программирование, идея решения проблем, реализует некоторые повторяющиеся проблемы кодирования через аспекты. Многие понимают, что аспекты понимаются через Spring, поэтому возникает непонимание, что Spring AOP и AOP приравниваются, но это не так.
Spring AOP
Весенний АОПпростоПосадочная реализация АОП, в основном обеспечивает реализацию АОП в контейнере Spring, и без Spring работать не будет. Spring AOP не является полным решением AOP.
Многие компоненты Spring такие, как Spring-Session, Spring-jdbc, Spring-Cache и т. д., могут решить некоторые общие требования, но будет много ограничений, Если вы хотите использовать более глубокие и гибкие функции реализации, вам все равно нужно использовать другие профессиональные компоненты/фреймворки.
SpringAOP по умолчанию реализован в режиме прокси, то есть JDK Proxy/CGLib. Я не буду вдаваться в подробности о прокси, JDK Proxy и CGLib.
AspectJ
Spring AOP не является полным решением AOP, в отличие от AspectJ. AspectJ вплетает аспекты в целевые классы в компиляторе
решение
Реализация SpringAop представлена выше, а решение выделено ниже.
Способ 1 — внедрить прокси-бин в себя
Для этого нет веской причины
@Autowired
@Lazy
private AsyncMethod asyncMethod;
public void testAsync() {
System.out.println(Thread.currentThread().getName());
// 调用注入的bean
asyncMethod.testAsnc3();
}
@Async
public void testAsnc3() {
System.out.println(Thread.currentThread().getName());
System.out.println("async3");
}
Note
Будет проблема циклической зависимости, используйте@Lazy
решать
Способ 2 -AopContext.currentProxy()
Получить текущий прокси-объект
использовать
Сначала нужно настроить@EnableAspectJAutoProxy(exposeProxy = true)
, позволяя получить прокси-класс в коде
public void testAsync() {
System.out.println(Thread.currentThread().getName());
System.out.println("async1");
((AsyncMethod)AopContext.currentProxy()).testAsnc2();
}
@Async
public void testAsnc2() {
System.out.println(Thread.currentThread().getName());
System.out.println("async2");
}
Принципиальный анализ
Эта реализация может смотреть на класс AopContext,
// 通过ThreadLocal来实现的
private static final ThreadLocal<Object> currentProxy = new NamedThreadLocal<Object>("Current AOP proxy");
Затем Spring Aop автоматически настраивает прокси, устанавливаяexposeProxy
проблема собственности.
Кто-то написал это, так что я больше не буду писать
Note
- Поскольку используется SpringAOP, будут ограничения на режим прокси.
- AopContext.currentProxy() использует ThreadLocal, поэтому он не может пересекать потоки.
- Ограничения на параметры bean-компонента, такие как методы создания прокси @Async, отличаются от других | методов
Способ 3 — использовать AspectJ напрямую
Поскольку проблема самовызова вызвана тем, что Spring AOP реализуется в режиме прокси, не будет ли она решена без использования режима прокси?
использовать
- переключиться в режим прокси
@EnableAsync(mode = AdviceMode.ASPECTJ)
- Добавьте зависимости пакета для ткачества аспекта.
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-instrument -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
- использовать
public void testAsync() {
System.out.println(Thread.currentThread().getName());
System.out.println("async1");
testAsnc2();
}
/**
* 测试ASPECTJ调用
*/
@Async
private void testAsnc2() {
System.out.println(Thread.currentThread().getName());
System.out.println("async2");
}
- Метод запуска AspectJ — компилятор вплетает аспект в целевой класс, а при запуске нужно добавить параметры java-агента
-Dserver.port=1000 -javaagent:${classpath}\spring-instrument-4.2.5.RELEASE.jar
-javaagent:${classpath}\aspectjweaver-1.8.8.jar
Суммировать
метод | ограничение |
---|---|
вызывающий сам себя | Ограничения режима прокси, такие как только публичные, нестатические методы |
AopContext.currentProxy() | 1. Ограничение режима прокси 2. Ограничение ThreadLocal, не может пересекать потоки 3. Ограничение настроек бина, например метод создания прокси @Async отличается от других |
AspectJ | Неограниченный, немного хлопотно использовать |
Обратите внимание на паблик-аккаунт [Abbot's Temple], как можно скорее получите обновление статьи и начните путь технической практики вместе с настоятелем
Ссылаться на
блог. Помогите мне. Тогда /2017/08/31/…
cloud.Tencent.com/developer/ ах…
F правильно A вы ошибаетесь.com/software-of…