AOP技术(2)


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 &#123;

    @Override
    public void sayHello(String str) &#123;
        // TODO Auto-generated method stub
        System.out.println("my is A object..."+str);
    &#125;
    @Override
    public void sayBye() &#123;
        // TODO Auto-generated method stub
        System.out.println("my is A object...bye byte");
    &#125;

&#125;

增加切片操作的类:

public class DemoAfterMethod implements AfterMethod
&#123;

    @Override
    public void say() &#123;
        // TODO Auto-generated method stub
       System.out.println("just a test aftermethod");
    &#125;

&#125;

中间代理类:

public class ProxyHelloTwo implements IHello
&#123;
    private IHello target;
    private BeforeMethod  before;
    private AfterMethod   after;


    public ProxyHelloTwo()
    &#123;

    &#125;
    public ProxyHelloTwo(IHello target,BeforeMethod before,
            AfterMethod after)
    &#123;
            this.target=target;
            this.before=before;
            this.after=after;
    &#125;

    @Override
    public void sayHello(String str) &#123;
        // TODO Auto-generated method stub

        if(this.before!=null) before.say();
        target.sayHello(str);// 调用被代理对象的方法
        if(this.after!=null)  after.say();

    &#125;

    @Override
    public void sayBye() &#123;

        target.sayBye();
    &#125;

&#125;

main函数:

public class ProxyBySelfSpring &#123;

    public static void main(String[] args) &#123;
        // TODO Auto-generated method stub
        IHello target=(IHello)SpringCore.getBean("proxy");
        target.sayHello("I like china!");
        target.sayBye();
    &#125;

&#125;

2、实现AOP的两种技术

2.1 三种切片类型

  1. AfterAdvice
public class AfterAdviceDemo implements AfterReturningAdvice
&#123;
    @Override
    public void afterReturning(Object arg0, Method arg1, Object[] arg2,
            Object arg3) throws Throwable &#123;
        // TODO Auto-generated method stub
        System.out.println("after advice demo.....");
    &#125;

&#125;
  1. BeforeAdvice
public class DemoBeforeAdvice implements MethodBeforeAdvice
&#123;
    @Override
    public void before(Method method, Object[] args, Object target)
        throws Throwable &#123;
        //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!");
    &#125;
&#125;
  1. RoundAdvice
public class RoundAdviceDemo implements MethodInterceptor &#123;

    @Override
    public Object invoke(MethodInvocation arg0) throws Throwable &#123;
        // TODO Auto-generated method stub
        System.out.println("round demo....");
        Object object= arg0.proceed();// 调用代理对象的方法
        System.out.println("after round demo....");
        return object;
    &#125;
&#125;

2.2 JDK动态代理技术

​ 应用场景:实现了接口的类。

​ 如何实现:定义Proxy类实现接口,重写接口的方法,从而增加切片。

实现了接口的类:

@Component
public class ServiceDemo implements IAopDemo&#123;
    private String name="hzhqian";
    private String url;

    public void setName(String name) &#123;
        this.name = name;
    &#125;

    public void setUrl(String url) &#123;
        this.url = url;
    &#125;

    public  void printName() &#123;
        System.out.println("name : " + this.name);
    &#125;

    public void printURL() &#123;
        System.out.println("company : " + this.url);
    &#125;

    public void printThrowException() &#123;
        throw new IllegalArgumentException();
    &#125;

    @Override
    public void printA() &#123;
        // TODO Auto-generated method stub
        System.out.println("interface A demo...");

    &#125;

    @Override
    public void PrintB() &#123;
        // TODO Auto-generated method stub
        System.out.println("interface B demo...");

    &#125;

&#125;

main函数:

public static void main(String[] args) 
   &#123;
     ApplicationContext appContext = new ClassPathXmlApplicationContext(
                new String[] &#123; "beans.xml" &#125;);


     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&#123;
    for(Field f:field)
    &#123;  
        System.out.print(f.getName()+", "+f.getType()+" # ");
        f.setAccessible(true);
        System.out.println(f.get(demo)+"  #"+f.getModifiers());
    &#125;
   &#125;catch(Exception e)
   &#123;
       e.printStackTrace();
   &#125;
      */
&#125;

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 &#123;

    private String name="hzhqian";
    private String url;
    protected  int  myName=99;

    public void setName(String name) &#123;
        this.name = name;
    &#125;

    public void setUrl(String url) &#123;
        this.url = url;
    &#125;

    public  void printName() &#123;
        System.out.println("name : " + this.name);
    &#125;

    public void printURL() &#123;
        System.out.println("company : " + this.url);
    &#125;

&#125;

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) &#123;
        // TODO Auto-generated method stub
        ApplicationContext appContext = new ClassPathXmlApplicationContext(
                new String[] &#123; "beans.xml" &#125;);

        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();
&#125;

​ 根据生成的字节码对象,调用getInterface()函数判断该类是否实现了接口,若实现了,则使用JDK动态代理技术,反之,则创建一个类继承被代理类,完成切片操作。

3、 小结

​ 上述两种技术的原理都是重写被代理类的方法,在上一节中的中间代理类Dyn被写到了配置文件中。通过解析配置文件这一方法,更加体现了可维护性。

​ 这个版本仍然存在问题,当被代理类中有多个方法时,每个方法都会被进行切片操作。


文章作者: kilig
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 kilig !
 上一篇
AOP技术(3) AOP技术(3)
1、通过xml配置文件实现AOP​ 流程: 将所有的切片操作放到一个类中。 在xml配置文件中,通过扫描器、手动配置两种方式,得到被代理类对象和切片类对象。 通过<aop:config>标签,配置切面,切入点以及增强哪些
2020-08-02
下一篇 
AOP技术(1) AOP技术(1)
1、AOP介绍​ AOP(Aspect-Oriented Programming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等
2020-07-31
  目录