1. 通过自己的spring内核实现AOP
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean name="before" class="com.hugeyurt.base.test.DemoBefore" />
<bean name="after" class="com.hugeyurt.base.test.DemoAfterMethod"/>
<bean name="aobj" class="com.hugeyurt.base.test.A"/>
<bean name="proxy" class="com.hugeyurt.base.test.ProxyHelloTwo">
<property name="target" ref="aobj"/>
<property name="before" ref="before"/>
<property name="after" ref="after"/>
</bean>
</beans>
通过解析这个配置文件,可以得到两个切片的对象,被代理的对象。然后使用接口对象去引用该中间代理类生成的对象,即可实现AOP功能。
实现接口的类A:
public class A implements IHello {
@Override
public void sayHello(String str) {
// TODO Auto-generated method stub
System.out.println("my is A object..."+str);
}
@Override
public void sayBye() {
// TODO Auto-generated method stub
System.out.println("my is A object...bye byte");
}
}
增加切片操作的类:
public class DemoAfterMethod implements AfterMethod
{
@Override
public void say() {
// TODO Auto-generated method stub
System.out.println("just a test aftermethod");
}
}
中间代理类:
public class ProxyHelloTwo implements IHello
{
private IHello target;
private BeforeMethod before;
private AfterMethod after;
public ProxyHelloTwo()
{
}
public ProxyHelloTwo(IHello target,BeforeMethod before,
AfterMethod after)
{
this.target=target;
this.before=before;
this.after=after;
}
@Override
public void sayHello(String str) {
// TODO Auto-generated method stub
if(this.before!=null) before.say();
target.sayHello(str);// 调用被代理对象的方法
if(this.after!=null) after.say();
}
@Override
public void sayBye() {
target.sayBye();
}
}
main函数:
public class ProxyBySelfSpring {
public static void main(String[] args) {
// TODO Auto-generated method stub
IHello target=(IHello)SpringCore.getBean("proxy");
target.sayHello("I like china!");
target.sayBye();
}
}
2、实现AOP的两种技术
2.1 三种切片类型
- AfterAdvice
public class AfterAdviceDemo implements AfterReturningAdvice
{
@Override
public void afterReturning(Object arg0, Method arg1, Object[] arg2,
Object arg3) throws Throwable {
// TODO Auto-generated method stub
System.out.println("after advice demo.....");
}
}
- BeforeAdvice
public class DemoBeforeAdvice implements MethodBeforeAdvice
{
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
//if(method.getName().equals("printName")) return ;
System.out.println("**********before****************");
System.out.println(method.getName());
System.out.println(target);
///method.invoke(target, args);
System.out.println("-------------------------------");
System.out.println("BeforeMethod : Before method finished!");
}
}
- RoundAdvice
public class RoundAdviceDemo implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation arg0) throws Throwable {
// TODO Auto-generated method stub
System.out.println("round demo....");
Object object= arg0.proceed();// 调用代理对象的方法
System.out.println("after round demo....");
return object;
}
}
2.2 JDK动态代理技术
应用场景:实现了接口的类。
如何实现:定义Proxy类实现接口,重写接口的方法,从而增加切片。
实现了接口的类:
@Component
public class ServiceDemo implements IAopDemo{
private String name="hzhqian";
private String url;
public void setName(String name) {
this.name = name;
}
public void setUrl(String url) {
this.url = url;
}
public void printName() {
System.out.println("name : " + this.name);
}
public void printURL() {
System.out.println("company : " + this.url);
}
public void printThrowException() {
throw new IllegalArgumentException();
}
@Override
public void printA() {
// TODO Auto-generated method stub
System.out.println("interface A demo...");
}
@Override
public void PrintB() {
// TODO Auto-generated method stub
System.out.println("interface B demo...");
}
}
main函数:
public static void main(String[] args)
{
ApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] { "beans.xml" });
IAopDemo demo =(IAopDemo) appContext.getBean("serviceProxy");
System.out.println(demo.getClass().getName());
System.out.println(demo instanceof IAopDemo);
System.out.println(demo.getClass().getSuperclass().getName());
System.out.println("------------------------------------");
demo.printA();
demo.PrintB();
/*
System.out.println("subject中的属性有:");
Field[] field=demo.getClass().getDeclaredFields();
try{
for(Field f:field)
{
System.out.print(f.getName()+", "+f.getType()+" # ");
f.setAccessible(true);
System.out.println(f.get(demo)+" #"+f.getModifiers());
}
}catch(Exception e)
{
e.printStackTrace();
}
*/
}
xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<bean id="demoService" class="com.hugeyurt.springAOP.ServiceDemo">
<property name="name" value="hugeyurt" />
<property name="url" value="hugeyurt.com" />
</bean>
<bean id="beforeDemo" class="com.hugeyurt.springAOP.DemoBeforeAdvice" />
<bean id="afterDemo" class="com.hugeyurt.springAOP.AfterAdviceDemo" />
<bean id="roundDemo" class="com.hugeyurt.springAOP.RoundAdviceDemo" />
<bean id="serviceProxy"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="demoService" />
<property name="interceptorNames">
<list>
<!--<value>beforeDemo</value> -->
<!-- <value>afterDemo</value> -->
<value>roundDemo</value>
</list>
</property>
</bean>
</beans>
xml文件中为实现了接口的类创建了一个对象,然后通过Proxy类进行切片操作,生成了serviceProxy对象,使用接口的对象引用serviceProxy,即可实现JDK动态代理。
2.3 字节码增强技术
应用场景:没有实现接口的类。
如何实现:定义一个子类继承被代理类,重写接口的方法,增加切片。
未实现接口的类:
@Component
public class ServiceDemo2 {
private String name="hzhqian";
private String url;
protected int myName=99;
public void setName(String name) {
this.name = name;
}
public void setUrl(String url) {
this.url = url;
}
public void printName() {
System.out.println("name : " + this.name);
}
public void printURL() {
System.out.println("company : " + this.url);
}
}
xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<bean id="demoService2" class="com.hugeyurt.springAOP.ServiceDemo2"/>
<bean id="beforeDemo" class="com.hugeyurt.springAOP.DemoBeforeAdvice" />
<bean id="afterDemo" class="com.hugeyurt.springAOP.AfterAdviceDemo" />
<bean id="roundDemo" class="com.hugeyurt.springAOP.RoundAdviceDemo" />
<bean id="serviceProxy1"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="demoService2" />
<property name="interceptorNames">
<list>
<value>beforeDemo</value>
<!-- <value>afterDemo</value>
<value>roundDemo</value> -->
</list>
</property>
</bean>
</beans>
main函数:
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] { "beans.xml" });
ServiceDemo2 demo2 =(ServiceDemo2) appContext.getBean("serviceProxy1");
System.out.println(demo2.getClass().getName());
System.out.println(demo2 instanceof IAopDemo);
System.out.println(demo2.getClass().getSuperclass().getName());
demo2.printName();
demo2.printURL();
}
根据生成的字节码对象,调用getInterface()
函数判断该类是否实现了接口,若实现了,则使用JDK动态代理技术,反之,则创建一个类继承被代理类,完成切片操作。
3、 小结
上述两种技术的原理都是重写被代理类的方法,在上一节中的中间代理类Dyn被写到了配置文件中。通过解析配置文件这一方法,更加体现了可维护性。
这个版本仍然存在问题,当被代理类中有多个方法时,每个方法都会被进行切片操作。