2024-05 spring-04-aop

This commit is contained in:
Vladimir Ivanov
2024-06-14 19:28:45 +03:00
parent 9d60c167de
commit ed0055dd72
76 changed files with 1722 additions and 0 deletions
@@ -0,0 +1,24 @@
target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/build/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ru.otus</groupId>
<artifactId>exercise</artifactId>
<version>1.0</version>
<properties>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<spring.version>6.0.9</spring.version>
<aspectj.version>1.9.19</aspectj.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<!-- можно не писать - она транзитивна spring-context -->
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,23 @@
package ru.otus.spring;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import ru.otus.spring.domain.Person;
import ru.otus.spring.service.PersonService;
@Configuration
@ComponentScan
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(Main.class);
PersonService service = context.getBean(PersonService.class);
Person ivan = service.getByName("Ivan");
System.out.println("name: " + ivan.getName() + " age: " + ivan.getAge());
}
}
@@ -0,0 +1,8 @@
package ru.otus.spring.dao;
import ru.otus.spring.domain.Person;
public interface PersonDao {
Person findByName(String name);
}
@@ -0,0 +1,14 @@
package ru.otus.spring.dao;
import org.springframework.stereotype.Repository;
import ru.otus.spring.domain.Person;
@Repository
public class PersonDaoSimple implements PersonDao {
@Override
public Person findByName(String name) {
return new Person(name, 18);
}
}
@@ -0,0 +1,20 @@
package ru.otus.spring.domain;
public class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
@@ -0,0 +1,13 @@
package ru.otus.spring.logging;
import org.aspectj.lang.JoinPoint;
public class LoggingAspect {
public void logBefore(JoinPoint joinPoint) {
System.out.println("Прокси : " + joinPoint.getThis().getClass().getName());
System.out.println("Класс : " + joinPoint.getTarget().getClass().getName());
System.out.println("Вызов метода : " + joinPoint.getSignature().getName());
}
}
@@ -0,0 +1,8 @@
package ru.otus.spring.service;
import ru.otus.spring.domain.Person;
public interface PersonService {
Person getByName(String name);
}
@@ -0,0 +1,21 @@
package ru.otus.spring.service;
import org.springframework.stereotype.Service;
import ru.otus.spring.dao.PersonDao;
import ru.otus.spring.domain.Person;
@Service
public class PersonServiceImpl implements PersonService {
private final PersonDao dao;
public PersonServiceImpl(PersonDao dao) {
this.dao = dao;
}
@Override
public Person getByName(String name) {
return dao.findByName(name);
}
}
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ru.otus</groupId>
<artifactId>aop-classwork</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<modules>
<module>exercise</module>
<module>solution</module>
</modules>
</project>
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ru.otus</groupId>
<artifactId>solution</artifactId>
<version>1.0</version>
<properties>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<spring.version>6.0.9</spring.version>
<aspectj.version>1.9.19</aspectj.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<!-- можно не писать - она транзитивна spring-context -->
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,25 @@
package ru.otus.spring;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import ru.otus.spring.domain.Person;
import ru.otus.spring.service.PersonService;
@EnableAspectJAutoProxy
@Configuration
@ComponentScan
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(Main.class);
PersonService service = context.getBean(PersonService.class);
Person ivan = service.getByName("Ivan");
System.out.println("name: " + ivan.getName() + " age: " + ivan.getAge());
}
}
@@ -0,0 +1,8 @@
package ru.otus.spring.dao;
import ru.otus.spring.domain.Person;
public interface PersonDao {
Person findByName(String name);
}
@@ -0,0 +1,16 @@
package ru.otus.spring.dao;
import org.springframework.stereotype.Repository;
import ru.otus.spring.domain.Person;
import ru.otus.spring.logging.LogMe;
@Repository
public class PersonDaoSimple implements PersonDao {
@Override
@LogMe
public Person findByName(String name) {
return new Person(name, 18);
}
}
@@ -0,0 +1,20 @@
package ru.otus.spring.domain;
public class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
@@ -0,0 +1,11 @@
package ru.otus.spring.logging;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogMe {
}
@@ -0,0 +1,19 @@
package ru.otus.spring.logging;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
@Before("@annotation(ru.otus.spring.logging.LogMe)")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Прокси : " + joinPoint.getThis().getClass().getName());
System.out.println("Класс : " + joinPoint.getTarget().getClass().getName());
System.out.println("Вызов метода : " + joinPoint.getSignature().getName());
}
}
@@ -0,0 +1,8 @@
package ru.otus.spring.service;
import ru.otus.spring.domain.Person;
public interface PersonService {
Person getByName(String name);
}
@@ -0,0 +1,21 @@
package ru.otus.spring.service;
import org.springframework.stereotype.Service;
import ru.otus.spring.dao.PersonDao;
import ru.otus.spring.domain.Person;
@Service
public class PersonServiceImpl implements PersonService {
private final PersonDao dao;
public PersonServiceImpl(PersonDao dao) {
this.dao = dao;
}
@Override
public Person getByName(String name) {
return dao.findByName(name);
}
}
+24
View File
@@ -0,0 +1,24 @@
target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/build/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
@@ -0,0 +1,3 @@
mvn clean package
java -jar target/aop-ctw-plain-1.0-jar-with-dependencies.jar
read -p "Press enter to continue"
@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ru.otus</groupId>
<artifactId>aop-ctw-plain</artifactId>
<version>1.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<aspectj.version>1.9.19</aspectj.version>
<aspectj.plugin.version>1.13.1</aspectj.plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>dev.aspectj</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>${aspectj.plugin.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>ru.otus.spring.Main</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>dev.aspectj</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>${aspectj.plugin.version}</version>
<configuration>
<complianceLevel>17</complianceLevel>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<showWeaveInfo>true</showWeaveInfo>
<verbose>true</verbose>
<Xlint>ignore</Xlint>
<encoding>UTF-8</encoding>
<weaveDirectories>
<weaveDirectory>${project.build.directory}/classes</weaveDirectory>
</weaveDirectories>
<forceAjcCompile>true</forceAjcCompile>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<!-- <goal>test-compile</goal> -->
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,25 @@
package ru.otus.spring;
import ru.otus.spring.dao.PersonDao;
import ru.otus.spring.dao.PersonDaoSimple;
import ru.otus.spring.domain.Person;
import ru.otus.spring.service.PersonService;
import ru.otus.spring.service.PersonServiceImpl;
/*
Запуск примера:
1. cd aop-demo/aop-ctw-plain/
2. mvn clean package
3. java -jar target/aop-ctw-plain-1.0-jar-with-dependencies.jar
*/
public class Main {
public static void main(String[] args) {
PersonDao personDao = new PersonDaoSimple();
PersonService service = new PersonServiceImpl(personDao);
Person ivan = service.getByName("Ivan");
System.out.println("name: " + ivan.getName() + " age: " + ivan.getAge());
}
}
@@ -0,0 +1,8 @@
package ru.otus.spring.dao;
import ru.otus.spring.domain.Person;
public interface PersonDao {
Person findByName(String name);
}
@@ -0,0 +1,11 @@
package ru.otus.spring.dao;
import ru.otus.spring.domain.Person;
public class PersonDaoSimple implements PersonDao {
@Override
public Person findByName(String name) {
return new Person(name, 18);
}
}
@@ -0,0 +1,20 @@
package ru.otus.spring.domain;
public class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
@@ -0,0 +1,17 @@
package ru.otus.spring.logging;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class LoggingAspect {
@Before("execution(* ru.otus.spring.dao.PersonDaoSimple.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Прокси : " + joinPoint.getThis().getClass().getName());
System.out.println("Класс : " + joinPoint.getTarget().getClass().getName());
System.out.println("Вызов метода : " + joinPoint.getSignature().getName());
}
}
@@ -0,0 +1,8 @@
package ru.otus.spring.service;
import ru.otus.spring.domain.Person;
public interface PersonService {
Person getByName(String name);
}
@@ -0,0 +1,18 @@
package ru.otus.spring.service;
import ru.otus.spring.dao.PersonDao;
import ru.otus.spring.domain.Person;
public class PersonServiceImpl implements PersonService {
private final PersonDao dao;
public PersonServiceImpl(PersonDao dao) {
this.dao = dao;
}
@Override
public Person getByName(String name) {
return dao.findByName(name);
}
}
@@ -0,0 +1,3 @@
mvn clean package
java -jar target/aop-ctw-1.0-jar-with-dependencies.jar
read -p "Press enter to continue"
@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ru.otus</groupId>
<artifactId>aop-ctw</artifactId>
<version>1.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.source>11</maven.compiler.source>
<spring.version>6.0.9</spring.version>
<aspectj.version>1.9.19</aspectj.version>
<aspectj.plugin.version>1.13.1</aspectj.plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<!-- можно не писать - она транзитивна spring-context -->
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>dev.aspectj</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>${aspectj.plugin.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>ru.otus.spring.Main</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>dev.aspectj</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>${aspectj.plugin.version}</version>
<configuration>
<complianceLevel>17</complianceLevel>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<showWeaveInfo>true</showWeaveInfo>
<verbose>true</verbose>
<Xlint>ignore</Xlint>
<encoding>UTF-8</encoding>
<weaveDirectories>
<weaveDirectory>${project.build.directory}/classes</weaveDirectory>
</weaveDirectories>
<forceAjcCompile>true</forceAjcCompile>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<!-- <goal>test-compile</goal> -->
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,30 @@
package ru.otus.spring;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import ru.otus.spring.domain.Person;
import ru.otus.spring.service.PersonService;
/*
Запуск примера:
1. cd aop-demo/aop-ctw/
2. mvn clean package
3. java -jar target/aop-ctw-1.0-jar-with-dependencies.jar
*/
@Configuration
@ComponentScan
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(Main.class);
PersonService service = context.getBean(PersonService.class);
Person ivan = service.getByName("Ivan");
System.out.println("name: " + ivan.getName() + " age: " + ivan.getAge());
}
}
@@ -0,0 +1,8 @@
package ru.otus.spring.dao;
import ru.otus.spring.domain.Person;
public interface PersonDao {
Person findByName(String name);
}
@@ -0,0 +1,14 @@
package ru.otus.spring.dao;
import org.springframework.stereotype.Repository;
import ru.otus.spring.domain.Person;
@Repository
public class PersonDaoSimple implements PersonDao {
@Override
public Person findByName(String name) {
return new Person(name, 18);
}
}
@@ -0,0 +1,20 @@
package ru.otus.spring.domain;
public class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
@@ -0,0 +1,17 @@
package ru.otus.spring.logging;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class LoggingAspect {
@Before("execution(* ru.otus.spring.dao.PersonDaoSimple.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Прокси : " + joinPoint.getThis().getClass().getName());
System.out.println("Класс : " + joinPoint.getTarget().getClass().getName());
System.out.println("Вызов метода : " + joinPoint.getSignature().getName());
}
}
@@ -0,0 +1,8 @@
package ru.otus.spring.service;
import ru.otus.spring.domain.Person;
public interface PersonService {
Person getByName(String name);
}
@@ -0,0 +1,21 @@
package ru.otus.spring.service;
import org.springframework.stereotype.Service;
import ru.otus.spring.dao.PersonDao;
import ru.otus.spring.domain.Person;
@Service
public class PersonServiceImpl implements PersonService {
private final PersonDao dao;
public PersonServiceImpl(PersonDao dao) {
this.dao = dao;
}
@Override
public Person getByName(String name) {
return dao.findByName(name);
}
}
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ru.otus</groupId>
<artifactId>aop-custom</artifactId>
<version>1.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<spring.version>6.0.9</spring.version>
<aspectj.version>1.9.19</aspectj.version>
</properties>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,69 @@
package ru.otus.demo;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import ru.otus.demo.aop.LoggingAspect;
import ru.otus.demo.aop.SimpleWeaver;
import ru.otus.demo.dao.BookDao;
import ru.otus.demo.dao.BookDaoSimple;
import ru.otus.demo.dao.PersonDao;
import ru.otus.demo.dao.PersonDaoSimple;
public class Main {
public static void main(String[] args) {
// Как будто Bean Definitions
List<Class<?>> beanDefinitions = List.of(SimpleWeaver.class, LoggingAspect.class,
PersonDaoSimple.class, BookDaoSimple.class);
// Как будто контекст
Map<Class<?>, Object> context = new HashMap<>();
beanDefinitions.stream()
// Создание бинов
.map(Main::createInstance)
// Постобработка, вивинг
.forEach(bean -> putBeanIntoContextAndApplyAspectIfNecessary(bean, context));
// Как будто достаем из контекста дао (уже с примененным аспектом)
PersonDao personDaoProxy = (PersonDao) context.get(PersonDao.class);
BookDao bookDaoProxy = (BookDao) context.get(BookDao.class);
// Используем сервисы
personDaoProxy.findByName("Вася");
System.out.println("-------------------------------------------------");
bookDaoProxy.findByTitle("Укротители велосипедов");
}
private static Object createInstance(Class<?> clazz) {
try {
return clazz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static Class<?> getInterfaceOrClass(Object o) {
if (o.getClass().getInterfaces().length > 0) {
return o.getClass().getInterfaces()[0];
}
return o.getClass();
}
private static void putBeanIntoContextAndApplyAspectIfNecessary(Object bean, Map<Class<?>, Object> context) {
// Если нет интерфейсов, то это наш вивер и аспект. Просто кладем в контекст
// (сам спринг естественно не такие штуки ориентируется, но у нас будет такое допущение)
Class<?> key = getInterfaceOrClass(bean);
if (!key.isInterface()) {
context.put(key, bean);
return;
}
// Если интерфейсы есть, то это наши дао и мы их вивим с аспектом. Результат кладем в контекст
SimpleWeaver weaver = (SimpleWeaver) context.get(SimpleWeaver.class);
LoggingAspect aspect = (LoggingAspect) context.get(LoggingAspect.class);
context.put(key, weaver.weave(bean, aspect));
}
}
@@ -0,0 +1,68 @@
package ru.otus.demo;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Collectors;
import org.springframework.cglib.proxy.Enhancer;
import ru.otus.demo.dao.PersonDao;
import ru.otus.demo.dao.PersonDaoSimple;
import ru.otus.demo.service.PersonService;
import ru.otus.demo.service.PersonServiceImpl;
public class MainSimple {
public static void main(String[] args) {
LoggingAspectSimple aspect = new LoggingAspectSimple();
PersonDao personDaoSimple = new PersonDaoSimple();
// JdkProxy
System.out.println("JdkProxy");
PersonDao personDaoJdkProxy = (PersonDao) Proxy.newProxyInstance(
MainSimple.class.getClassLoader(),
personDaoSimple.getClass().getInterfaces(),
new java.lang.reflect.InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] methodArgs) throws Throwable {
aspect.logBefore(personDaoSimple.getClass(), proxy.getClass(), method, methodArgs);
return method.invoke(personDaoSimple, methodArgs);
}
}
);
PersonService personService = new PersonServiceImpl(personDaoJdkProxy);
personService.getByName("Вася");
// CglibProxy (Spring edition, работает в Java 17 без плясок)
System.out.println("\n\nCglibProxy (Spring edition)");
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(PersonDaoSimple.class);
enhancer.setCallback(new org.springframework.cglib.proxy.InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] methodArgs) throws Throwable {
aspect.logBefore(personDaoSimple.getClass(), proxy.getClass(), method, methodArgs);
return method.invoke(personDaoSimple, methodArgs);
}
});
PersonDao personDaoCgLibProxy = (PersonDao) enhancer.create();
personService = new PersonServiceImpl(personDaoCgLibProxy);
personService.getByName("Игорь");
}
private static class LoggingAspectSimple {
public void logBefore(Class<?> originalClass, Class<?> proxyClass, Method method, Object[] methodArgs) {
System.out.println("Прокси : " + proxyClass.getName());
System.out.println("Класс : " + originalClass.getName());
System.out.println("Вызов метода : " + method.getName());
System.out.println("Аргументы метода : " + Arrays.stream(methodArgs)
.map(Objects::toString)
.collect(Collectors.joining(", ")));
}
}
}
@@ -0,0 +1,20 @@
package ru.otus.demo.aop;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Collectors;
import org.aspectj.lang.JoinPoint;
public class LoggingAspect {
public void logBefore(JoinPoint joinPoint) {
System.out.println("Прокси : " + joinPoint.getThis().getClass().getName());
System.out.println("Класс : " + joinPoint.getTarget().getClass().getName());
System.out.println("Вызов метода : " + joinPoint.getSignature().getName());
System.out.println("Аргументы метода : " + Arrays.stream(joinPoint.getArgs())
.map(Objects::toString)
.collect(Collectors.joining(", ")));
}
}
@@ -0,0 +1,24 @@
package ru.otus.demo.aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
public class SimpleAOPInvocationHandler implements InvocationHandler {
private final Object target;
private final LoggingAspect aspect;
public SimpleAOPInvocationHandler(Object target, LoggingAspect aspect) {
this.target = target;
this.aspect = aspect;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
JoinPoint joinPoint = new SimpleJoinPoint(target,
proxy, args, method);
aspect.logBefore(joinPoint);
return method.invoke(target, args);
}
}
@@ -0,0 +1,67 @@
package ru.otus.demo.aop;
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.SourceLocation;
public class SimpleJoinPoint implements JoinPoint {
private final Object targetClass;
private final Object proxyClass;
private final Object[] args;
private final Signature targetMethodSignature;
public SimpleJoinPoint(Object target, Object proxy, Object[] args,
Method targetMethod) {
this.targetClass = target;
this.proxyClass = proxy;
this.args = args;
this.targetMethodSignature = new SimpleSignature(targetMethod);
}
@Override
public String toShortString() {
throw new UnsupportedOperationException();
}
@Override
public String toLongString() {
throw new UnsupportedOperationException();
}
@Override
public Object getThis() {
return proxyClass;
}
@Override
public Object getTarget() {
return targetClass;
}
@Override
public Object[] getArgs() {
return args;
}
@Override
public Signature getSignature() {
return targetMethodSignature;
}
@Override
public SourceLocation getSourceLocation() {
throw new UnsupportedOperationException();
}
@Override
public String getKind() {
throw new UnsupportedOperationException();
}
@Override
public StaticPart getStaticPart() {
throw new UnsupportedOperationException();
}
}
@@ -0,0 +1,43 @@
package ru.otus.demo.aop;
import java.lang.reflect.Method;
import org.aspectj.lang.Signature;
public class SimpleSignature implements Signature {
private final Method targetMethod;
public SimpleSignature(Method targetMethod) {
this.targetMethod = targetMethod;
}
@Override
public String toShortString() {
throw new UnsupportedOperationException();
}
@Override
public String toLongString() {
throw new UnsupportedOperationException();
}
@Override
public String getName() {
return targetMethod.getName();
}
@Override
public int getModifiers() {
throw new UnsupportedOperationException();
}
@Override
public Class<?> getDeclaringType() {
throw new UnsupportedOperationException();
}
@Override
public String getDeclaringTypeName() {
throw new UnsupportedOperationException();
}
}
@@ -0,0 +1,16 @@
package ru.otus.demo.aop;
import java.lang.reflect.Proxy;
import ru.otus.demo.Main;
public class SimpleWeaver {
@SuppressWarnings("unchecked")
public <T> T weave(T classInstance, LoggingAspect aspect) {
return (T) Proxy.newProxyInstance(
Main.class.getClassLoader(),
classInstance.getClass().getInterfaces(),
new SimpleAOPInvocationHandler(classInstance, aspect)
);
}
}
@@ -0,0 +1,8 @@
package ru.otus.demo.dao;
import ru.otus.demo.domain.Book;
public interface BookDao {
Book findByTitle(String title);
}
@@ -0,0 +1,10 @@
package ru.otus.demo.dao;
import ru.otus.demo.domain.Book;
public class BookDaoSimple implements BookDao {
@Override
public Book findByTitle(String title) {
return new Book(title);
}
}
@@ -0,0 +1,8 @@
package ru.otus.demo.dao;
import ru.otus.demo.domain.Person;
public interface PersonDao {
Person findByName(String name);
}
@@ -0,0 +1,12 @@
package ru.otus.demo.dao;
import ru.otus.demo.domain.Person;
public class PersonDaoSimple implements PersonDao {
@Override
public Person findByName(String name) {
return new Person(name, 18);
}
}
@@ -0,0 +1,14 @@
package ru.otus.demo.domain;
public class Book {
private final String title;
public Book(String name) {
this.title = name;
}
public String getTitle() {
return title;
}
}
@@ -0,0 +1,28 @@
package ru.otus.demo.domain;
public class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
@@ -0,0 +1,8 @@
package ru.otus.demo.service;
import ru.otus.demo.domain.Book;
public interface BookService {
Book getByTitle(String title);
}
@@ -0,0 +1,17 @@
package ru.otus.demo.service;
import ru.otus.demo.dao.BookDao;
import ru.otus.demo.domain.Book;
public class BookServiceImpl implements BookService {
private final BookDao bookDao;
public BookServiceImpl(BookDao bookDao) {
this.bookDao = bookDao;
}
@Override
public Book getByTitle(String title) {
return bookDao.findByTitle(title);
}
}
@@ -0,0 +1,8 @@
package ru.otus.demo.service;
import ru.otus.demo.domain.Person;
public interface PersonService {
Person getByName(String name);
}
@@ -0,0 +1,18 @@
package ru.otus.demo.service;
import ru.otus.demo.dao.PersonDao;
import ru.otus.demo.domain.Person;
public class PersonServiceImpl implements PersonService {
private final PersonDao dao;
public PersonServiceImpl(PersonDao dao) {
this.dao = dao;
}
@Override
public Person getByName(String name) {
return dao.findByName(name);
}
}
@@ -0,0 +1,3 @@
mvn clean package
java -javaagent:c:/Users/User/.m2/repository/org/aspectj/aspectjweaver/1.9.19/aspectjweaver-1.9.19.jar -jar target/aop-ltw-1.0-jar-with-dependencies.jar
read -p "Press enter to continue"
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ru.otus</groupId>
<artifactId>aop-ltw</artifactId>
<version>1.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<spring.version>6.0.9</spring.version>
<aspectj.version>1.9.19</aspectj.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<!-- можно не писать - она транзитивна spring-context -->
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>ru.otus.spring.Main</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,32 @@
package ru.otus.spring;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import ru.otus.spring.domain.Person;
import ru.otus.spring.service.PersonService;
/*
Запуск примера:
1. В IDEA, вменю запуска выбираем "Edit Configurations..."
2. В поле "VM options" вносим "-javaagent:${путь.до.m2}\.m2\repository\org\aspectj\aspectjweaver\1.9.8\aspectjweaver-1.9.8.jar",
где ${путь.до.m2} это путь до репозитория мавен на текущем компьютере.
Пример: "-javaagent:c:\Users\MyUserName\.m2\repository\org\aspectj\aspectjweaver\1.9.9.1\aspectjweaver-1.9.9.1.jar".
Кавычки не вносим)
3. Запускаем Main
*/
@Configuration
@ComponentScan
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(Main.class);
PersonService service = context.getBean(PersonService.class);
Person ivan = service.getByName("Ivan");
System.out.println("name: " + ivan.getName() + " age: " + ivan.getAge());
}
}
@@ -0,0 +1,8 @@
package ru.otus.spring.dao;
import ru.otus.spring.domain.Person;
public interface PersonDao {
Person findByName(String name);
}
@@ -0,0 +1,17 @@
package ru.otus.spring.dao;
import org.springframework.stereotype.Repository;
import ru.otus.spring.domain.Person;
@Repository
public class PersonDaoSimple implements PersonDao {
public PersonDaoSimple() {
System.out.println(this.getClass().getClassLoader());
}
@Override
public Person findByName(String name) {
return new Person(name, 18);
}
}
@@ -0,0 +1,20 @@
package ru.otus.spring.domain;
public class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
@@ -0,0 +1,17 @@
package ru.otus.spring.logging;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class LoggingAspect {
@Before("execution(* ru.otus.spring.dao.PersonDaoSimple.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Прокси : " + joinPoint.getThis().getClass().getName());
System.out.println("Класс : " + joinPoint.getTarget().getClass().getName());
System.out.println("Вызов метода : " + joinPoint.getSignature().getName());
}
}
@@ -0,0 +1,8 @@
package ru.otus.spring.service;
import ru.otus.spring.domain.Person;
public interface PersonService {
Person getByName(String name);
}
@@ -0,0 +1,21 @@
package ru.otus.spring.service;
import org.springframework.stereotype.Service;
import ru.otus.spring.dao.PersonDao;
import ru.otus.spring.domain.Person;
@Service
public class PersonServiceImpl implements PersonService {
private final PersonDao dao;
public PersonServiceImpl(PersonDao dao) {
this.dao = dao;
}
@Override
public Person getByName(String name) {
return dao.findByName(name);
}
}
@@ -0,0 +1,13 @@
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "https://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver options="-showWeaveInfo -verbose">
<include within="ru.otus.spring.dao.*"/>
<include within="ru.otus.spring.logging.*"/>
</weaver>
<aspects>
<aspect name="ru.otus.spring.logging.LoggingAspect"/>
</aspects>
</aspectj>
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ru.otus</groupId>
<artifactId>aop-native</artifactId>
<version>1.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<spring.version>6.0.9</spring.version>
<aspectj.version>1.9.19</aspectj.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<!-- можно не писать - она транзитивна spring-context -->
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,23 @@
package ru.otus.spring;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import ru.otus.spring.domain.Person;
import ru.otus.spring.service.PersonService;
@Configuration
@ComponentScan
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(Main.class);
PersonService service = context.getBean(PersonService.class);
Person ivan = service.getByName("Ivan");
System.out.println("name: " + ivan.getName() + " age: " + ivan.getAge());
}
}
@@ -0,0 +1,17 @@
package ru.otus.spring.config;
import static org.springframework.beans.factory.config.BeanDefinition.ROLE_INFRASTRUCTURE;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
@Role(ROLE_INFRASTRUCTURE)
@Configuration
public class CommonNativeAopConfig {
@Bean
public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
return new DefaultAdvisorAutoProxyCreator();
}
}
@@ -0,0 +1,40 @@
package ru.otus.spring.config;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.otus.spring.dao.PersonDaoSimple;
@Configuration
public class LoggingAspectConfig {
public Pointcut personDaoSimpleLoggingAspectPointcut() {
return new Pointcut() {
@Override
public ClassFilter getClassFilter() {
return clazz -> clazz.equals(PersonDaoSimple.class);
}
@Override
public MethodMatcher getMethodMatcher() {
return MethodMatcher.TRUE;
}
};
}
MethodBeforeAdvice personDaoSimpleLoggingAspectBeforeAdvice() {
return (method, objects, o) -> System.out.println("Ура! Вызов метода : " + method.getName());
}
@Bean
public DefaultPointcutAdvisor personDaoSimpleLoggingAspectAdvisor() {
return new DefaultPointcutAdvisor(personDaoSimpleLoggingAspectPointcut(),
personDaoSimpleLoggingAspectBeforeAdvice());
}
}
@@ -0,0 +1,8 @@
package ru.otus.spring.dao;
import ru.otus.spring.domain.Person;
public interface PersonDao {
Person findByName(String name);
}
@@ -0,0 +1,14 @@
package ru.otus.spring.dao;
import org.springframework.stereotype.Repository;
import ru.otus.spring.domain.Person;
@Repository
public class PersonDaoSimple implements PersonDao {
@Override
public Person findByName(String name) {
return new Person(name, 18);
}
}
@@ -0,0 +1,20 @@
package ru.otus.spring.domain;
public class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
@@ -0,0 +1,8 @@
package ru.otus.spring.service;
import ru.otus.spring.domain.Person;
public interface PersonService {
Person getByName(String name);
}
@@ -0,0 +1,21 @@
package ru.otus.spring.service;
import org.springframework.stereotype.Service;
import ru.otus.spring.dao.PersonDao;
import ru.otus.spring.domain.Person;
@Service
public class PersonServiceImpl implements PersonService {
private final PersonDao dao;
public PersonServiceImpl(PersonDao dao) {
this.dao = dao;
}
@Override
public Person getByName(String name) {
return dao.findByName(name);
}
}
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ru.otus</groupId>
<artifactId>aop-demo</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<modules>
<module>aop-ctw</module>
<module>aop-ctw-plain</module>
<module>aop-custom</module>
<module>aop-ltw</module>
<module>aop-native</module>
</modules>
</project>