一、应用背景
在看此文章之前,你可能已经知道了,spring是通过Before、After、AfterRunning、AfterThrowing以及Around 共5中通知方式为目标方法增加切面功能,比如一个需要在目标类执行一个目标方法之前和之后分别打印一份日志,就可以建立一个切面在这个方法前后打印日志。但是如果我想在此目标类中再增加一个目标方法是,该怎么办呢?
最简单的办法就是在建立此目标类的时候,增加此方法。但是如果原目标类非常复杂,动一发而牵全身。我们可以为需要添加的方法建立一个类,然后建一个代理类,同时代理该类和目标类。用一个图来表示
图中,A就是原目标类,B就是新添加的方法所在的类,通过建立一个代理类同时代理A和B,调用者调用该代理时,就可以同时A和B中的方法了。
正好spring已经为我们做好这些事情,我们只需要在spring 下乘凉就可以了,通过@DeclareParents注解就可以实现该功能。下面通过代码来演示
二、代码实例
假设我们的目标类是一个女人,她的核心方法为喜欢帅哥,但是我们又要为该方法添加一个新的功能,建立一个新的雌性类,该类中的方法为非常喜欢吃,把此功能添加到原目标类中。
1、创建接口
原目类为(A类)
package com.lzj.spring.annotation;
public interface Person {
void likePerson();
}
package com.lzj.spring.annotation;
import org.springframework.stereotype.Component;
@Component("women")
public class Women implements Person {
@Override
public void likePerson() {
System.out.println("我是女生,我喜欢帅哥");
}
}
新添加的类(B类):
package com.lzj.spring.annotation;
import org.springframework.stereotype.Component;
public interface Animal {
void eat();
}
package com.lzj.spring.annotation;
import org.springframework.stereotype.Component;
@Component
public class FemaleAnimal implements Animal {
@Override
public void eat() {
System.out.println("我是雌性,我比雄性更喜欢吃零食");
}
}
2、代理类配置
package com.lzj.spring.annotation;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class AspectConfig {
//"+"表示person的所有子类;defaultImpl 表示默认需要添加的新的类
@DeclareParents(value = "com.lzj.spring.annotation.Person+", defaultImpl = FemaleAnimal.class)
public Animal animal;
}
3、Bean的配置类
该类的目的是为了能在spring容器中能注入已装载的Bean.
package com.lzj.spring.annotation;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan
@EnableAspectJAutoProxy
public class AnnotationConfig {
}
4、测试类
package com.lzj.spring.annotation;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MainTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AnnotationConfig.class);
Person person = (Person) ctx.getBean("women");
person.likePerson();
Animal animal = (Animal)person;
animal.eat();
}
}
出结果为:
我是女生,我喜欢帅哥
我是雌性,我比雄性更喜欢吃零食
你看,是否通过代理实现了原目标类和新添加的类中的目标方法。