通过注解引入新功能
之前的文章(Spring面向切面编程 AOP,实现AOP注解和XML配置的小例子)实现了在不修改类的情况下,为方法新增功能。这篇文章将讲述,在不修改类的情况下,如何为类新增方法。
我们先来看一个实现此功能的小例子,然后再来解析它是如何实现此功能的。
package aop;
public interface IPerformance {
public void perform();
}
package aop;
import org.springframework.stereotype.Component;
@Component
public class Performance implements IPerformance{
@Override
public void perform() {
System.out.println("表演开始");
}
}
package aop;
public interface IShow {
public void show();
}
package aop;
import org.springframework.stereotype.Component;
@Component
public class Show implements IShow{
@Override
public void show() {
System.out.println("演出结束");
}
}
package aop;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class DeclareParent {
@DeclareParents(value = "aop.IPerformance+",defaultImpl=Show.class)
public IShow ishow;
}
pom.xml 个人做项目的pom.xml文件,如有不需要这么多的,可自行删除。
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.liangyu.aop</groupId>
<artifactId>aopDemo</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>aopDemo Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.5.RELEASE</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.1.5.RELEASE</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.5.RELEASE</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.5.RELEASE</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.5.RELEASE</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.4.RELEASE</version>
<type>pom</type>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/cglib/cglib-nodep -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.2.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.6.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>aopDemo</finalName>
</build>
</project>
package aop;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@ComponentScan
@EnableAspectJAutoProxy
@Configuration
public class AOPConfig {
}
package aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
public class AopTest {
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext("aop");
IPerformance perfomance = (IPerformance) ac.getBean("performance");
perfomance.perform();
IShow show = (IShow)perfomance;
show.show();
}
}
运行结果如下:
表演开始
演出结束
可以看出已经实现来为IPerformance这个接口新增来一个show方法。
那么实现此功能引入了一个新的注解:@DeclareParents
@DeclareParents注解由三部分组成:
- value属性指定了哪种类型的bean要引入该接口。
- defaultImpl属性指定了为引入功能提供实现的类。
- @DeclareParents注解所标注的属性指明了要引入的接口。
为了更好了理解上面这段话,把此实现类移动至下方供参考理解。
package aop;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class DeclareParent {
@DeclareParents(value = "aop.IPerformance+",defaultImpl=Show.class)
public IShow ishow;
}
注意:
该功能实现,只能使用在接口实现的方法,如果此方法没有实现接口,那么注解无效。例如Performance不实现任何接口,只是一个普通的类。同样,Show也不实现任何接口,也是一个普通的类,那么这种方式就会报错。