Master Spring AOP’s @DeclareParents: Dynamic Interface Injection in Spring Boot 3
This article explains how Spring AOP’s @DeclareParents introduces new interfaces to proxied beans at runtime, walks through defining interfaces, implementations, aspect configuration, testing with Spring Boot 3, and also covers perthis and pertarget aspect instantiation models for fine‑grained lifecycle control.
Spring AOP provides a special type enhancement called "Introductions" (implemented via @DeclareParents ) that allows an aspect to dynamically introduce new interfaces to a proxied object, enabling the object to implement methods declared by those interfaces at runtime.
1. Introducing Interfaces
Define the interface that the target class should implement.
<code>public interface DAO {
void remove();
}</code>Implement the interface.
<code>public class DefaultDAO implements DAO {
@Override
public void remove() {
System.out.println("默认删除功能");
}
}</code>Create the aspect using @DeclareParents to bind the interface to the target class.
<code>@Aspect
public class LogAspect {
@Pointcut("@annotation(log)")
private void recordLog(Log log) {}
// Bind PersonService to DAO interface
@DeclareParents(value = "com.pack.aop.PersonService", defaultImpl = DefaultDAO.class)
private DAO dao;
@Around("recordLog()")
public Object aroundLog(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("日志执行前...");
Object ret = pjp.proceed();
System.out.println("日志执行后...");
return ret;
}
}</code>Define the service class.
<code>@Service
public class PersonService {
public void save() {
System.out.println("保存Person对象");
}
}</code>Test the behavior.
<code>@SpringBootTest
public class AppTest {
private final PersonService ps;
public AppTest(PersonService ps) { this.ps = ps; }
@Test
public void testSave() {
ps.save();
if (ps instanceof DAO dao) {
dao.remove();
}
}
}</code>Output:
<code>日志执行前...
保存Person对象
日志执行后...
默认删除功能</code>2. Aspect Instantiation Models
Spring AOP supports perthis, pertarget, and pertypewithin models. The perthis model creates a separate aspect instance for each target object that matches the pointcut; pertarget does the same for each unique target object.
Example of perthis model:
<code>@Component
@Scope("prototype")
@Aspect("perthis(execution(* com.pack.aop.DAO.*(..)))")
public class LogAspect {
@Before("bean(*Service)")
public void beforeLog(JoinPoint jp) {
System.out.println("before 记录日志 - " + this);
}
}</code>Define business objects implementing DAO.
<code>public interface DAO { void save(); }
public class PersonService implements DAO {
public void save() { System.out.println("保存Person对象"); }
}
public class StudentService implements DAO {
public void save() { System.out.println("保存Student对象"); }
}</code>Test both services.
<code>@SpringBootTest
public class AppTest {
@Resource private PersonService ps;
@Resource private StudentService ss;
@Test
public void testAll() {
ps.save();
System.out.println("===============" );
ss.save();
}
}</code>Output:
<code>before 记录日志 - com.pack.aop.LogAspect@3ed242a4
保存Person对象
====================
before 记录日志 - com.pack.aop.create.LogAspect@73a2e526
保存Student对象</code>These models are rarely needed unless fine‑grained control over aspect lifecycle is required.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.