AspectPostProcessor.java
package sprout.aop;
import net.sf.cglib.proxy.Enhancer;
import org.reflections.Reflections;
import org.reflections.scanners.Scanners;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.reflections.util.FilterBuilder;
import sprout.aop.advice.AdviceFactory;
import sprout.aop.advisor.Advisor;
import sprout.aop.advisor.AdvisorRegistry;
import sprout.aop.annotation.Aspect;
import sprout.beans.annotation.Component;
import sprout.beans.processor.BeanPostProcessor;
import sprout.context.ApplicationContext;
import sprout.context.CtorMeta;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
@Component
public class AspectPostProcessor implements BeanPostProcessor {
private final AdvisorRegistry advisorRegistry;
private final ApplicationContext container;
private final AdviceFactory adviceFactory;
private final ProxyFactory proxyFactory;
private final AtomicBoolean initialized = new AtomicBoolean(false); // 초기화 여부 플래그
private List<String> basePackages; // 스캔할 기본 패키지 목록
public AspectPostProcessor(AdvisorRegistry advisorRegistry, ApplicationContext container, AdviceFactory adviceFactory, ProxyFactory proxyFactory) {
this.advisorRegistry = advisorRegistry;
this.container = container;
this.adviceFactory = adviceFactory;
this.proxyFactory = proxyFactory;
}
public void initialize(List<String> basePackages) {
System.out.println("Initializing AspectPostProcessor with basePackages: " + basePackages);
if (initialized.compareAndSet(false, true)) { // 한 번만 초기화되도록 보장
this.basePackages = basePackages;
scanAndRegisterAdvisors(); // 초기화 시점에 Advisor 스캔 및 등록
}
}
private void scanAndRegisterAdvisors() {
if (basePackages == null || basePackages.isEmpty()) {
System.err.println("Warning: basePackages not set for AspectPostProcessor. No aspects will be scanned.");
return;
}
ConfigurationBuilder configBuilder = new ConfigurationBuilder();
for (String pkg : basePackages) {
configBuilder.addUrls(ClasspathHelper.forPackage(pkg));
}
configBuilder.addScanners(Scanners.TypesAnnotated, Scanners.SubTypes);
configBuilder.addClassLoaders(ClasspathHelper.contextClassLoader(), ClasspathHelper.staticClassLoader());
FilterBuilder filter = new FilterBuilder();
for (String pkg : basePackages) {
filter.includePackage(pkg);
}
configBuilder.filterInputsBy(filter);
Reflections reflections = new Reflections(configBuilder);
Set<Class<?>> aspectClasses = reflections.getTypesAnnotatedWith(Aspect.class);
for (Class<?> aspectClass : aspectClasses) {
List<Advisor> advisorsForThisAspect = createAdvisorsFromAspect(aspectClass);
System.out.println(aspectClass.getName() + " has " + advisorsForThisAspect.size() + " advisors: " + advisorsForThisAspect);
for (Advisor advisor : advisorsForThisAspect) {
advisorRegistry.registerAdvisor(advisor);
}
}
System.out.println("advisorRegistry#getAllAdvisors()" + advisorRegistry.getAllAdvisors());
}
private List<Advisor> createAdvisorsFromAspect(Class<?> aspectClass) {
List<Advisor> advisors = new ArrayList<>();
Supplier<Object> aspectSupplier = () -> container.getBean(aspectClass);
for (Method m : aspectClass.getDeclaredMethods()) {
adviceFactory.createAdvisor(aspectClass, m, aspectSupplier)
.ifPresent(advisors::add);
}
return advisors;
}
@Override
public Object postProcessAfterInitialization(String beanName, Object bean) {
Class<?> targetClass = bean.getClass();
// 모든 메서드를 순회하며 해당 메서드에 적용될 Advisor가 있는지 확인
boolean needsProxy = false;
for (Method method : targetClass.getMethods()) {
if (Modifier.isPublic(method.getModifiers()) && !Modifier.isStatic(method.getModifiers())) {
if (!advisorRegistry.getApplicableAdvisors(targetClass, method).isEmpty()) {
needsProxy = true;
break;
}
}
}
if (needsProxy) {
System.out.println("Applying AOP proxy to bean: " + beanName + " (" + targetClass.getName() + ")");
CtorMeta meta = container.lookupCtorMeta(bean);
return proxyFactory.createProxy(targetClass, bean, advisorRegistry, meta);
}
return bean;
}
}