• 3-Spring AOP


    AOP

    1-什么是AOP

    • AOP Aspect Oriented Programing 面向切面编程

    • AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视,事务管理、安全检查、缓存)。

    2-AOP的底层实现原理

    3-AOP的相关术语

    public class USerDaoImpl implements UserDao{
        public void save(User user){
        
        }
        public void update(User user){
        
        }
        public void find( ){
        
        }
        public void delete(User user){
        
        }
    }
    

    Joinpoint (连接点):指的是可以被拦截的点。增删改查这些方法都可以被增强,这些方法称为是连接点。

    Pointcut (切入点):指的是真正被拦截的点。只想对save方法进行增强(做权限校验),save方法称为是切入点。

    Advice (通知):拦截后要做的事情。对save方法进行校验,权限校验的方法称为通知。

    Target(目标):被增强的对象

    weaving(织入):将Advice应用到Target的过程。将权限校验应用到UserDaoImpl的Save方法的这个过程。

    Proxy(代理):被应用了增强后,产生了一个代理对象。

    Aspect(切面):就是切入点和通知的组合。

    4.JDK动态代理

    测试改代码需要导入Juint的jar包

    public interface UserDao {
        public void save();
    
        public void update();
    
        public void delete();
    
        public void find();
    }
    
    * * *
    public class UserDaoImpl implements UserDao {
        public void save() {
            System.out.println("保存用户...");
        }
    
        public void update() {
            System.out.println("修改用户...");
        }
    
        public void delete() {
            System.out.println("删除用户...");
        }
    
        public void find() {
            System.out.println("查询用户...");
        }
    }
    
    * * *
    public class MyJdkProxy implements InvocationHandler{
        private UserDao userDao;
    
        public MyJdkProxy(UserDao userDao){
            this.userDao = userDao;
        }
    
        public Object createProxy(){
            Object proxy = Proxy.newProxyInstance(userDao.getClass().getClassLoader(),userDao.getClass().getInterfaces(),this);
            return proxy;
        }
    
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if("save".equals(method.getName())){
                System.out.println("权限校验...");
                return method.invoke(userDao,args);
            }
            return method.invoke(userDao,args);
        }
    }
    
    * * *
    public class SpringDemo1 {
        @Test
        public void demo1(){
            UserDao userDao = new UserDaoImpl();
    
            UserDao proxy = (UserDao)new MyJdkProxy(userDao).createProxy();
            proxy.save();
            proxy.update();
            proxy.delete();
            proxy.find();
        }
    }
    

    5.使用CGLIB生成代理

    pom.xml核心jar包
    <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.12</version>
        </dependency>
    
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-beans</artifactId>
          <version>4.2.4.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-expression</artifactId>
          <version>4.2.4.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-core</artifactId>
          <version>4.2.4.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>4.2.4.RELEASE</version>
        </dependency>
         <!--aop联盟的包-->
        <dependency>
          <groupId>aopalliance</groupId>
          <artifactId>aopalliance</artifactId>
          <version>1.0</version>
        </dependency>
        <!--spring aop的包-->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-aop</artifactId>
          <version>4.2.4.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-test</artifactId>
          <version>4.2.4.RELEASE</version>
        </dependency>
    
    public class ProductDao {
        public void save(){
            System.out.println("保存商品...");
        }
    
        public void update(){
            System.out.println("修改商品...");
        }
    
        public void delete(){
            System.out.println("删除商品...");
        }
    
        public void find(){
            System.out.println("查询商品...");
        }
    }
    
    * * *
    public class MyCglibProxy implements MethodInterceptor{
    
        private ProductDao productDao;
    
        public MyCglibProxy(ProductDao productDao){
            this.productDao = productDao;
        }
    
        public Object createProxy(){
            // 1.创建核心类
            Enhancer enhancer = new Enhancer();
            // 2.设置父类
            enhancer.setSuperclass(productDao.getClass());
            // 3.设置回调
            enhancer.setCallback(this);
            // 4.生成代理
            Object proxy = enhancer.create();
            return proxy;
        }
    
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            if("save".equals(method.getName())){
                System.out.println("权限校验===================");
                return methodProxy.invokeSuper(proxy,args);
            }
            return methodProxy.invokeSuper(proxy,args); //调用父类
        }
    }
    
    * * *
    public class SpringDemo2 {
    
        @Test
        public void demo1(){
            ProductDao productDao = new ProductDao();
    
            ProductDao proxy = (ProductDao) new MyCglibProxy(productDao).createProxy();
            proxy.save();
            proxy.update();
            proxy.delete();
            proxy.find();
        }
    }
    

    6-代理知识总结

    1- Spring在运行期,生成动态代理对象,不需要特殊的编译器

    2-Spring AOP的底层就是通过JDK动态代理或CGLib动态代理技术 为目标Bean
    执行横向织入.

    • 若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类
      代理。
    • 若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。

    3-程序中应优先对接口创建代理,便于程序解耦维护

    4-标记为final的方法,不能被代理,因为无法进行覆盖

    • JDK动态代理,是针对接口生成子类,接口中方法不能使用final修饰
    • CGLib 是针对目标类生产子类,因此类或方法 不能使final的

    5-Spring只支持方法连接点,不提供属性连接

    6-Spring AOP增强类型

    1-前置通知

    • 在目标方法执行前实施增强

    2-后置通知

    • 在目标方法执行后实施增强

    3-环绕通知

    • 在目标方法执行前后实施增强

    4-异常抛出通知

    • 在方法抛出异常后实施增强

    7- Spring AOP切面类型

    1.Advisor : 代表一般切面,Advice本身就是一个切面,对目标类所有方法进
    行拦截。

    public interface StudentDao {
        public void find();
    
        public void save();
    
        public void update();
    
        public void delete();
    }
    
    * * *
    public class StudentDaoImpl implements  StudentDao {
        public void find() {
            System.out.println("学生查询...");
        }
    
        public void save() {
            System.out.println("学生保存...");
        }
    
        public void update() {
            System.out.println("学生修改...");
        }
    
        public void delete() {
            System.out.println("学生删除...");
        }
    }
    
    * * *
    public class MyBeforeAdvice implements MethodBeforeAdvice {
        public void before(Method method, Object[] args, Object target) throws Throwable {
            System.out.println("前置增强======================");
        }
    }
    
    * * *
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext.xml")
    public class SpringDemo3 {
    
        // @Resource(name="studentDao")
        @Resource(name="studentDaoProxy")
        private StudentDao studentDao;
    
        @Test
        public void demo1(){
            studentDao.find();
            studentDao.save();
            studentDao.update();
            studentDao.delete();
        }
    }
    
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!--配置目标类=======================-->
        <bean id="studentDao" class="com.imooc.aop.demo3.StudentDaoImpl"/>
    
        <!--前置通知类型=====================-->
        <bean id="myBeforeAdvice" class="com.imooc.aop.demo3.MyBeforeAdvice"/>
    
        <!--Spring的AOP 产生代理对象-->
        <bean id="studentDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
            <!--配置目标类-->
            <property name="target" ref="studentDao"/>
            <!--实现的接口-->
            <property name="proxyInterfaces" value="com.imooc.aop.demo3.StudentDao"/>
            <!--采用拦截的名称-->
            <property name="interceptorNames" value="myBeforeAdvice"/>
            <property name="optimize" value="true"></property>
        </bean>
    </beans>
    

    2.PointcutAdvisor : 代表具有切点的切面,可以指定拦截目标类哪些方法

    3.IntroductionAdvisor : 代表引介切面,针对引介通知而使用切面

  • 相关阅读:
    Sql 字符串按指定字符转多行(表值函数)
    C# 默认打印机设置
    Sql server 触发器状态查询
    指定周转对应日期
    Java发送HttpRequest
    Java实现手机号码归属地判别
    MySQL导入.sql文件及常用命令
    解释和编译的区别
    Java中的static关键字解析
    内存堆和栈的区别
  • 原文地址:https://www.cnblogs.com/Guard9/p/11105503.html
Copyright © 2020-2023  润新知