实现aop: 动态代理和cglib

*****

1,动态代理

public interface UserDao {
    void save();
}

public class UserDaoImpl implements UserDao {

    private String name;
    
    public void save() {
        System.out.println("save() is called, name: "+name);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    
}

代理工厂

ProxyFactory.java

package com.maple.util;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import com.maple.dao.UserDao;
import com.maple.dao.impl.UserDaoImpl;

public class ProxyFactory implements InvocationHandler {

    private Object target;
    
    public Object createUserDao(Object target){
        this.target=target;
        return Proxy.newProxyInstance(this.target.getClass().getClassLoader(),
                        this.target.getClass().getInterfaces(), this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println(proxy.getClass().getName());
        Object result=null;
        UserDaoImpl userDao=(UserDaoImpl)this.target;
        if(userDao.getName()!=null){
            result=method.invoke(userDao, args);
        }else{
            System.out.println("the name is null");
        }
        return result;
    }

}

测试

@Test
    public void test() {
        ProxyFactory pf=new ProxyFactory();
        UserDaoImpl u=new UserDaoImpl();
        u.setName("maple");
        UserDao userDao=(UserDao) pf.createUserDao(u);
        userDao.save();
    }

输出

$Proxy5
save() is called, name: maple

2,cglib

UserDaoImpl2.java不实现接口

package com.maple.dao.impl;


public class UserDaoImpl2{

    private String name;
    
    public void save() throws InterruptedException {
        Thread.sleep(3000);
        System.out.println("save() is called, name: "+name);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    public void raiseException(){
        throw new RuntimeException("this is test");
    }
    
}

CglibFactory.java

package com.maple.util;

import java.lang.reflect.Method;

import com.maple.dao.impl.UserDaoImpl2;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CglibFactory implements MethodInterceptor {

    private Object target;
    public Object createUserDao(Object target){
        this.target=target;
        Enhancer enhancer=new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
    
    @Override
    public Object intercept(Object proxy, Method method, Object[] args,
            MethodProxy methodProxy) throws Throwable {
        UserDaoImpl2 userDao=(UserDaoImpl2)target;
        System.out.println("begin");
        if(userDao.getName()!=null){
            method.invoke(target, args);
        }else{
            System.out.println("the name is null");
        }
        System.out.println("end");
        return null;
    }

}

测试代码:

@Test
    public void test2() throws InterruptedException{
        CglibFactory cf=new CglibFactory();
        UserDaoImpl2 temp=new UserDaoImpl2();
        UserDaoImpl2 userDao=(UserDaoImpl2)cf.createUserDao(temp);
        userDao.save();
        temp.setName("aa");
        userDao=(UserDaoImpl2)cf.createUserDao(temp);
        userDao.save();
    }

结果:

begin
the name is null
end
begin
save() is called, name: aa
end

3,spring综合了动态代理和cglib

UserDaoImpl,java,UserDaoImpl2.java同上

定义一个切面类MyInterceptor.java

package com.maple.util;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class MyInterceptor {
    //返回值任意,该包下面的所有类的所有方法,方法的参数个数任意
    @Pointcut("execution ( * com.maple.dao.impl.*.*(..))")
    public void anyMethod(){}
    
    @Before("anyMethod()")//执行符合切点的方法前执行
    public void before(){
        System.out.println("before()");
    }
    
    @After("anyMethod()")
    public void after(){
        System.out.println("after()");
    }
    
    @Around("anyMethod()")
    public void Around(ProceedingJoinPoint pjp) throws Throwable{
        long start=System.currentTimeMillis();
        System.out.println("begin around()");
        pjp.proceed();
        System.out.println("end around()");
        long end=System.currentTimeMillis();
        System.out.println("the time is "+(end-start));
    }
    @Before("anyMethod() && args(name)")
    public void before(String name){
        System.out.println("before(name): the name is:"+name);
    }
    
    @AfterReturning(pointcut="anyMethod()",returning="result")
    public void afterReturning(String result){
        System.out.println("the result is "+result);
    }
    
    @AfterThrowing(pointcut="anyMethod()",throwing="e")
    public void afterThrowing(Exception e){
        e.printStackTrace();
    }
    
}

测试

@Test
    public void test3() throws InterruptedException{
        ApplicationContext context=new ClassPathXmlApplicationContext("/beans.xml");
        UserDao userDao=(UserDao) context.getBean("userDaoImpl");
        //userDao.save();
        UserDaoImpl2 userDao2=(UserDaoImpl2) context.getBean("userDaoImpl2");
        //userDao2.save();
        userDao2.setName("hhh");
        //userDao2.raiseException();
        //System.out.println(userDao2.getName());
    
    }

在spring的配置文件beans.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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd           
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/tx 
           http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">
        <aop:aspectj-autoproxy/> <!-- spring打开aop功能 -->
        <bean id="userDaoImpl" class="com.maple.dao.impl.UserDaoImpl"/>
        <bean id="userDaoImpl2" class="com.maple.dao.impl.UserDaoImpl2"/>
        <bean id="myInterceptor444" class="com.maple.util.MyInterceptor"/>
        
        
</beans>

结果:

before()
before(name): the name is:hhh
begin around()
after()
end around()
the time is 0
the result is null

如果留下userDao2.save(),其他调用注释,则结果如下:

before()
begin around()
save() is called, name: null
after()
end around()
the time is 1
the result is null

注:1,在配置文件中如果没有对切面类的bean的定义,则不会执行切面类中的那些方法如before(),??

2,2个before方法都执行了,然后around开始,执行方法,执行after,around结束,执行afterReturning()

*****

有问题在公众号【清汤袭人】找我,时常冒出各种傻问题,然一通百通,其乐无穷,一起探讨


原文地址:https://www.cnblogs.com/qingmaple/p/4124784.html