SpringAOP实现之动态代理

归结到底就是通过反射实现AOP,实现 InvocationHandler 类的   public Object invoke(Object proxy, Method method, Object[] args)  {;}方法;
通过IOC模式将AOP配置到xml

Spring中AOP是怎么实现的呢?
Spring中AOP的有两种实现方式:
1、JDK动态代理
2、Cglib动态代理

Spring实现面向切面的逻辑:

切面(Aspect):其实就是共有功能的实现。如日志切面、权限切面、事务切面等。在实际应用中通常是一个存放共有功能实现的普通Java类,之所以能被AOP容器识别成切面,是在配置中指定的。

 

通知(Advice):是切面的具体实现。以目标方法为参照点,根据放置的地方不同,可分为前置通知(Before)、后置通知(AfterReturning)、异常通知(AfterThrowing)、最终通知(After)与环绕通知(Around)5种。在实际应用中通常是切面类中的一个方法,具体属于哪类通知,同样是在配置中指定的。

 

连接点(Joinpoint):就是程序在运行过程中能够插入切面的地点。例如,方法调用、异常抛出或字段修改等,但Spring只支持方法级的连接点。

 

切入点(Pointcut):用于定义通知应该切入到哪些连接点上。不同的通知通常需要切入到不同的连接点上,这种精准的匹配是由切入点的正则表达式来定义的。

 

目标对象(Target):就是那些即将切入切面的对象,也就是那些被通知的对象。这些对象中已经只剩下干干净净的核心业务逻辑代码了,所有的共有功能代码等待AOP容器的切入。

 

代理对象(Proxy):将通知应用到目标对象之后被动态创建的对象。可以简单地理解为,代理对象的功能等于目标对象的核心业务逻辑功能加上共有功能。代理对象对于使用者而言是透明的,是程序运行过程中的产物。

 

织入(Weaving):将切面应用到目标对象从而创建一个新的代理对象的过程。这个过程可以发生在编译期、类装载期及运行期,当然不同的发生点有着不同的前提条件。譬如发生在编译期的话,就要求有一个支持这种AOP实现的特殊编译器;发生在类装载期,就要求有一个支持AOP实现的特殊类装载器;只有发生在运行期,则可直接通过Java语言的反射机制与动态代理机制来动态实现。



代理类和被代理类实现共同的接口(或继承),代理类中存有指向被代理类的索引,实际执行时通过调用代理类的方法、实际执行的是被代理类的方法。



一个例子:
------------------------------ ------------------------------

cmd

进入E 盘

E:

进入相关文件目录

cd /src/main/java/com/springAOP

tree /f

tree /f F:\...\src\main\java\com\springAOP

------------------------------------------com.springAOP包下文件结构

│  UserServiceTest.java

├─aop

│      LogInterceptor.java

├─dao

│  │  UserDAO.java

│  └─impl

│          UserDAOImpl.java

├─model

│      User.java

└─service

        UserService.java 
 

 

 

 

UserServiceTest.java

package com.springAOP;

import com.springAOP.aop.LogInterceptor;
import com.springAOP.dao.UserDAO;
import com.springAOP.dao.impl.UserDAOImpl;
import com.springAOP.model.User;
import com.springAOP.service.UserService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.lang.reflect.Proxy;

/**
 * Created by Y on 2019/11/7.
 */

public class UserServiceTest {

@Test
public void testProxy() throws Exception{//代理测试
    UserDAO userDAO = new UserDAOImpl();
    LogInterceptor logInterceptor= new LogInterceptor();//NEW一个代理对象
    logInterceptor.setTarget(userDAO); //把需要代理的对象交给代理对象处理
    //调用Proxy类的静态方法 newProxyInstance
    //返回值是代理对象,该代理对象实现了被代理对象的方法
    UserDAO  userDAOProxy=(UserDAO)Proxy.newProxyInstance(userDAO.getClass().getClassLoader(),new Class[]{UserDAO.class},logInterceptor);
    UserDAO  userDAOProxy2=(UserDAO)Proxy.newProxyInstance(userDAO.getClass().getClassLoader(),userDAO.getClass().getInterfaces(),logInterceptor);
    //上面 userDAOProxy、userDAOProxy2产生的相同结果,产生被代理

        System.out.println(userDAOProxy.getClass());
    System.out.println(userDAOProxy.getClass().getName());
    System.out.println(userDAOProxy.getClass().getInterfaces());
    System.out.println(userDAOProxy.getClass().getInterfaces().getClass().getName());
    System.out.println(userDAOProxy.getClass().getInterfaces().getClass().getInterfaces());
    System.out.println(userDAOProxy.getClass().getClassLoader());

    userDAOProxy.delete(new User());//返回值是代理对象,该代理对象实现了被代理对象的方法 所以可以直接调用被代理类 的方法
        userDAOProxy2.save(new User());
}


}

 

 

LogInterceptor.java

 

package com.springAOP.aop;

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

/**
 * Created by Y on 2019/11/7.
 * 
代理
 
*/
public class LogInterceptor implements InvocationHandler {
    private Object target;

    public Object getTarget() {
        return target;
    }

    public void setTarget(Object target) {
        this.target = target;
    }

    public void beforeMethod(Method method){

        //System.out.println("save start...");
        System.out.println(method.getName() +"  start...代理被调用");
    }
    public void afterMethod(Method method){

        //System.out.println("save start...");
        System.out.println(method.getName() +"  end...代理被调用");
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        beforeMethod(method);
        System.out.println(this.getClass().getName()+"================================== target:" +target+"  args:"+args);
        method.invoke(target,args);
        afterMethod(method);
        return null;
    }
}

 

 

UserDAO.java

package com.springAOP.dao;

import com.springAOP.model.User;

/**
 * Created by Y on 2019/11/7.
 */

public interface UserDAO {
    public void save(User user);
    public void delete(User user);
}

 

 

UserDAOImpl.java

package com.springAOP.dao.impl;

import com.springAOP.aop.LogInterceptor;
import com.springAOP.dao.UserDAO;
import com.springAOP.model.User;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;

/**
 * Created by Y on 2019/11/7.
 */

//@Component(value = "userDAO")  //userDAOImpl  组件  可以看为另一个类的资源   在UserService注解key  @Resource(name = "userDAO")
//@Component("userDAO")
//@Component(value = "userDAO")
@Repository(value = "userDAO")
public class UserDAOImpl implements UserDAO {
    @Override
    public void save(User user) {
        //Hibernate
        //JDBC
        //XML
        //NetWork
       // new LogInterceptor().beforeMethod(null);
        //userDAO.save(user);
        System.out.println(this.getClass().getName()+"-----: user saved!");
    }

    @Override
    public void delete(User user) {
        System.out.println(this.getClass().getName()+"-----: user deleted!");
    }

}

 

 

User.java

package com.springAOP.model;

/**
 * Created by Y on 2019/11/7.
 */

public class User {
    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

 
/*
Run...

"D:\Program Files\jdk1.6.0_43\bin\java"........;E:\M2\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar" com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 com.springAOP.UserServiceTest,testProxy

class com.sun.proxy.$Proxy5

com.sun.proxy.$Proxy5

[Ljava.lang.Class;@9664a1

[Ljava.lang.Class;

[Ljava.lang.Class;@1a8c4e7

sun.misc.Launcher$AppClassLoader@1a46e30

delete  start...代理被调用

com.springAOP.aop.LogInterceptor================================== target:com.springAOP.dao.impl.UserDAOImpl@1172e08  args:[Ljava.lang.Object;@cf2c80

com.springAOP.dao.impl.UserDAOImpl-----: user deleted!

delete  end...代理被调用

save  start...代理被调用

com.springAOP.aop.LogInterceptor================================== target:com.springAOP.dao.impl.UserDAOImpl@1172e08  args:[Ljava.lang.Object;@1729854

com.springAOP.dao.impl.UserDAOImpl-----: user saved!

save  end...代理被调用

 

Process finished with exit code 0


*/














↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓Spring 注入切面,但一般都会在xml中配置↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

package com.springAOP.aop;

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

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.aspectj.lang.annotation.Before;


/**
* Created by Y on 2019/11/7.
*
* Spring 自动代理
*/
//@Aspect //切面
@Component //必须要初始化才能使用
@Aspect
public class LogInterceptorAspect implements InvocationHandler {
private Object target;

public Object getTarget() {
return target;
}

public void setTarget(Object target) {
this.target = target;
}

//@Pointcut("execution(public * com.itsoft.action..*.*(..))")
@Pointcut("execution(public * com.springAOP.dao.impl.UserDAOImpl.save(com.springAOP.model.User))")
public void recordLog(){}


//方法上面的切面逻辑(可以是属性 方法等)
@Before("execution(public void com.springAOP.dao.impl.UserDAOImpl.save(com.springAOP.model.User))") //该注解导致异常
//@Before("execution(* com.springAOP.dao.impl.UserDAOImpl.save(..))")
//@Before("recordLog()")
public void beforeMethod(Method method){
//System.out.println("save start...");
System.out.println(method.getName() +" start...代理被调用Aspect");
}
@After("recordLog()")
public void afterMethod(Method method){
//System.out.println("save start...");
System.out.println(method.getName() +" end...代理被调用Aspect");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
beforeMethod(method);
System.out.println(this.getClass().getName()+"================================== target:" +target+" args:"+args);
method.invoke(target,args);
afterMethod(method);
return method;
}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值