一、静态代理设计模式

1.为什么需要代理设计模式
1.1问题

  • 在JavaEE分层开发过程中,哪个层次对于我们来讲最重要

    DAO—>Service–>Controller
    JavaEE分层开发中,最为重要的是Service Service业务层

  • Service层中包含了哪些代码?

        Service层中 =核心功能代码(几十行 上百行)+额外功能代码(附加功能)1.核心功能业务运算DAO调用2.额外功能不属于业务可有可无代码量小例如:事务、日志、性能。。。
  • 额外功能书写在Service层中好不好?

    Service层的调用者(controller):需要在Service层书写额外功能软件设计者:Service层不需要额外功能
    
  • 现实生活中 的解决方式

    2.代理设计模式
    2.1概念

    通过代理类,为原始类(目标)增加额外功能
    好处:利于原始类(目标)的维护

    2.2名词解释

        1.目标类 原始类指的是 业务类(核心功能 --->业务运算 DAO调用)2.目标方法  原始方法目标类(原始类)中的方法 就是目标方法(原始方法)3.额外功能(附加功能) 日志,事务,性能
    

    2.3代理开发的核心要素

    代理类=目标类(原始类)+额外功能+原始类(目标类)实现相同的接口
    房东---->public interface UserService{m1(){}m2(){}}UserServiceImpl implements UserService{m1(){}m2(){}}
    

    2.4编码

    静态代理: 为每一个原始类,手工编写一个代理类(.java .class)

    2.5静态代理存在的问题

       1.静态类文件过多,不利于项目管理UserServiceImpl    UserServiceProxyOrderServiceImpl   OrderServiceProxy2.额外功能维护性差代理类中 额外功能修改复杂(麻烦)
    

二、Spring的动态代理开发

1.Spring动态代理的概念

概念:通过代理类为原始类(目标类)增加额外功能
好处:利于原始类(目标类)的维护

2.搭建开发环境

     <dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.1.14.RELEASE</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.8.8</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.3</version></dependency>

3.Spring动态代理的开发步骤
①创建原始对目标对象

public class UserServiceImpl implements UserService {@Overridepublic void register(User user) {System.out.println("UserServiceImpl.register===核心业务代码注册 调用DAO");}@Overridepublic boolean login(String name, String password) {System.out.println("UserServiceImpl.login======核心业务代码登录 调用DAO");return false;}
}
<bean id="userService" class="com.myspring.proxy.UserServiceImpl" />

②、额外功能
MethodBeforeAdvice接口

额外的功能书写在接口的实现中,运行在原始方法之前运行额外功能

 public class Before implements MethodBeforeAdvice {/*作用:需要把运行在原始方法执行之前运行的额外功能,书写在before方法中*/@Overridepublic void before(Method method, Object[] objects, Object o) throws Throwable {System.out.println("======额外功能=====");}
}
<bean id="before" class="com.myspring.dynamic.Before" />

③、定义切入点

切入点:额外功能加入的位置目的:由程序员根据自己的需要,决定额外功能加入给哪个原始方法
registe / longin
简单的测试:所有方法都作为切入点都加入额外的功能。
    <aop:config><!--定义切入的方式--><aop:pointcut id="pc" expression="execution(* *(..))"/></aop:config>

④、组装(②、③整合)

 表达的含义:所有方法 都加入before的额外功能<aop:advisor advice-ref="before" pointcut-ref="pc"/>
这是④的完整配置<aop:config><!--定义切入的方式--><aop:pointcut id="pc" expression="execution(* *(..))"/><aop:advisor advice-ref="before" pointcut-ref="pc"/></aop:config>

⑤、调用

目的:获得Sporing工厂的动态代理对象,并进行调用ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/applicationContext.xml");注意:1.Spring的工厂通过原始对象的id值获得的是代理对象2.获得代理对象后,可以通过声明接口类型,进行对象的存储UserService userService = applicationContext.getBean("userService", UserService.class);userService.login("bugz","123456");userService.register(new User("bugz","123456"));

4.动态代理细节分析
①、Spring创建的动态代理类在那里?

Spring框架在运行时,通过动态字节码技术,在JVM创建的,运行在JVM内部,等程序结束后,会和JVM一起消失。
————————————————————————————————————————————————————
什么叫动态字节码技术:通过第三方动态字节码框架,在JVM中创建对应类的字节码,进而创建对象,当虚拟机结束,动态字节码跟着消失。
—————————————————————————————————————————————————
结论:动态代理不需要定义类文件,都是JVM运行过程中动态创建的,所以不会造成静态代理,类文件数量过多,影响项目管理的问题。

②、动态代理编程简化代理的开发

在额外功能不变的前提下,创建其他目标类(原始类)的代理对象时,只需要指定原始(目标)对象即可。

③动态代理额外功能的维护性大大增强

三、Spring动态代理详解

1.额外功能的详解

  • MethodBeforeAdvice分析
   1.MethodBeforeAdvice接口作用:额外功能运行在原始方法之前,进行额外功能操作。public class Before implements MethodBeforeAdvice {/*作用:需要把运行在原始方法执行之前运行的额外功能,书写在before方法中方法参数介绍:Method method: 额外功能所增加给的那个原始方法Object[] objects: 额外功能所增加给的那个原始方法的参数。Object o:额外功能所增加给的那个原始对象*/@Overridepublic void before(Method method, Object[] objects, Object o) throws Throwable {System.out.println("======额外功能=====");}
}
——————————————————————————————————————————————————————————————————————————————————————2.before方法中的三个参数在实战中该如何使用before方法中的参数,在实战中,会根据需要进行使用,不一定都会用到,也有可能都不用。
  • MethodInterceptor(方法拦截器)
 methodinterceptor接口:额外功能可以根据需要运行在原始方法执行 前、后、前后。-------------------------------------------------------------------public class Around  implements MethodInterceptor {/*invoke方法的作用:额外功能书写在invoke额外功能可以加在  原始方法之前原始方法之后原始方法之前and之后确定:原始方法怎么执行methodeINvocation.proceed();参数:MethodInvocation methodInvocation:额外功能所增加给的那个原始方法返回值:原始方法的返回值*/@Overridepublic Object invoke(MethodInvocation methodInvocation) throws Throwable {System.out.println("+++++++++++额外功能运行在之前+++++++++");Object proceed = methodInvocation.proceed();return proceed;}}

额外功能运行在原始代码方法执行之后

    @Overridepublic Object invoke(MethodInvocation methodInvocation) throws Throwable {Object proceed = methodInvocation.proceed();System.out.println("+++++++++++额外功能运行在之后+++++++++");return proceed;}

额外功能运行在原始代码方法执行之前、之后。

 什么样的额外功能,运行在原始方法之前,之后都要添加?  例:事务@Overridepublic Object invoke(MethodInvocation methodInvocation) throws Throwable {System.out.println("+++++++++++额外功能运行在之前+++++++++");Object proceed = methodInvocation.proceed();System.out.println("+++++++++++额外功能运行在之后+++++++++");return proceed;}

额外功能运行在原始方法抛出异常的时候

    @Overridepublic Object invoke(MethodInvocation methodInvocation) throws Throwable {Object proceed = null;try {proceed = methodInvocation.proceed();} catch (Throwable throwable) {System.out.println("+++++++++++ 抛出异常时的 额外功能+++++++++");throwable.printStackTrace();}return proceed;}

MethodInterceptor影响原始方法的返回值

原始方法的返回值,直接作为invoke方法的返回值返回,MethodInterceptor不会影响原始方法的返回值
MethodInterceptor影响原始方法的返回值
Invoke方法的返回值,不要直接返回原始方法的运行结果即可。@Overridepublic Object invoke(MethodInvocation methodInvocation) throws Throwable {System.out.println("+++++++++++额外功能+++++++++");Object proceed = methodInvocation.proceed();return false;}

2.切入点详解

切入点决定额外功能加入位置(方法)
<aop:pointcut id="pc" expression="execution(* *(..))"/>
execution(* *(..))  --->匹配了所有方法 a b c1.execution() 切入点函数
2.* *(..) 切入点表达式

2.1切入点表达式
①、方法切入点表达式

* *(..) -->所有方法
*  --->修饰符 返回值
*  --->方法名
() --->参数表
.. --->对于参数没有要求(参数有没有,参数有几个都行,参数是什么类型的都行)
  • 定义login方法的切入点

    * login(..)
    #定义register作为切入点
    * register(..)
    
  • 定义long方法且login方法有两个字符串类型的参数 作为切入点
    * login(String,String)
    #注意:非Java.lang包中的类型,必须要写全限定名
    * register(com.xxx.xxx.User)
    # ..可以和具体的参数类型连用
    * login(String,..) -> login(String)/login(String,String)/login(String,com.xxx.User)
    
  • 精准方法切入点限定
    修饰符 返回值 包.类.方法(参数)
    *            com.xxx.xxx.login()
    *            com.xxx.xxx.login(String,String)
    

②、类切入点

指定特定类作为切入点(额外功能加入的位置),自然这个类中的所有方法,都会加上额外的功能

  • 语法1

    #类中所有的方法加入了额外功能
    * com.xx.xx.UserServiceImpl.*(..)
    
  • 语法2
     #忽略包1.类只存在一级包 com.UserServiceImpl* *.UserServiceImpl.*(..)2.类存在多级包 com.xxx.xxx.xxx.UserServiceImpl* *..UserServiceImpl.*(..)
    

③、包切入点 实战

指定包作为额外功能加入的位置,自然包中所有类及其方法都会加入额外功能

  • 语法1

    #切入包中的所有类,必须在xxx中,不能在xxx包的子包中
    * com.a.xxx.*.*(..)
    
  • 语法2

    #切入点当前包及其子包都生效
    * com.a.xxx..*.*(..)
    

2.2切入点函数

切入点函数:用于执行切入点表达式

①、execution

最为重要的切入点函数,功能最全
执行 方法切入点表达式 类切入点表达式 包切入点表达式弊端:execution执行切入点表达式,书写麻烦execution(* com.xxx.xxx..*.*(..))
注意:     其他的切入点函数 简化execution书写复杂度,功能上完全一致

②、args

作用:主要用于函数(方法)参数的匹配
切入点:例如---方法参数必须得是2个字符串类型的参数execution(* *(String,String))args(String,String)

③、within

作用:主要用于进行类、包切入点表达式的匹配
切入点:UserServiceImpl这个类execution(* *..UserServiceImpl.*(..))within(*..UserServiceImpl)execution(* com.xx.xx..*.*(..))within(com.xx.xx..*)

④、@annotation

作用:为具有特殊注解的方法加入额外功能
<aop:pointcut id="pc" expression="@annotation(com.xx.Log)"/>

⑤、切入点函数的逻辑运算

指的是整合多个切入点函数一起配合工作,进而完成更为复杂的需求

  • and与操作
 案例:login 同时 参数2个字符串1.exection(* login(String,String))2.exection(* login(.)) and args(String,String)注意 与操作不同用于同种类型的切入点函数案例:register方法和login方法作为切入点exection(* login(..)) or execution(* register(..))
  • or或操作
 案例:register方法和login方法作为切入点exection(* login(..)) or execution(* register(..))

四、AOP编程

1.AOP编程

AOP(Aspect Oriented Programming) 面向切面编程 = Spring动态代理开发
以切面为基本单位的程序开发,通过切面间的彼此协同,相互调用,完成程序的构建
切面 = 切入点+额外功能

OOP(Object Oriented Programming) 面向对象编程 JAVA
以对象为基本单位的程序开发,通过对象间的彼此协同,相互调用,完成程序的构建

POP(Procedure Oriented Programming) 面向过程(方法、函数)编程 c语言
以过程为单位的程序开发,通过过程间的彼此协同,相互调用,完成程序的构建。

AOP的概念:本质就是Spring的动态代理开发,通过代理类为原始类增加额外功能。
好处:利于原始类的维护
注意:AOP编程不可能取代OOP,OOP编程有意补充。

2.AOP编程的开发步骤

1.原始对象
2.额外功能(MethodInterceptor)
3.切入点
4.组装切面(额外功能+切入点)

3.切面的名词解释

切面 = 切入点+额外功能
几何学:面=点+相同性质

五、AOP底层实现原理

1.核心问题

1.AOP如何创建动态代理类(动态字节码技术)
2.Spring工厂如何加工创建代理类对象通过原始类对象的id值,获得的是代理对象

2.动态代理类的创建
2.1、JDK的动态代理

  • Proxy.newProxyInstance方法参数详解


  • 编码
   public class TestJDKProxy {public static void main(String[] args) {//1.创建原始对象UserServiceImpl userService = new UserServiceImpl();InvocationHandler invocationHandler = new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("====log====");//原始方法运行Object invoke = method.invoke(userService, args);return invoke;}};//2.JDK创建动态代理UserService  userService1 =(UserService) Proxy.newProxyInstance(UserService.class.getClassLoader(),userService.getClass().getInterfaces(),invocationHandler);userService1.login("bugz","123");userService1.register(new User("bugz","123"));/*细节问题:1.借用类加载器  UserService/TestJDKProxy2.JDK8.x前  需要这样写 final UserServiceImpl userService = new UserServiceImpl();*/}

2.2 CGlib动态代理

CGlib创建动态代理的原理:父子继承关系创建代理对象,原始类作为父类,代理类作为子类,这样既可以保证二者方法一致,同时在代理类中提供新的实现(额外功能+原始方法)

  • 编码
import com.myspring.proxy.User;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class TestCglib {public static void main(String[] args) {//1.创建原始对象UserService userService = new UserService();/*2.通过cglib的方式创建动态代理对象JDK创建代理方式 Proxy.newProxyInstance(classloader,interfaces,invocationhandler)Enhancer.setClassLoader();Enhancer.setSuperClass();Enhancer.setCallback();---->MethodInterceptor(cglib)Enhancer.create()--->代理*/Enhancer enhancer = new Enhancer();enhancer.setClassLoader(TestCglib.class.getClassLoader());enhancer.setSuperclass(userService.getClass());MethodInterceptor methodInterceptor = new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {System.out.println("------cglib new log--------");Object invoke = method.invoke(userService, args);return invoke;}};enhancer.setCallback(methodInterceptor);UserService userServiceProxy=(UserService) enhancer.create();userServiceProxy.login("bugz","123456");userServiceProxy.register(new User());}
}
  • 总结

1.JDK动态代理 Proxy.newProxyInstance() ------------通过接口创建代理的实现类
2.Cglib动态代理 Enhancer---------------------------------通过继承父类创建代理类

3.Spring工厂如何加工原始对象

  • 思路分析
  • 编码
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class ProxyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return null;}//使用jdk代理模拟工厂的代理@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {InvocationHandler invocationHandler = new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("---模拟代理的额外功能---");System.out.println(beanName);Object invoke = method.invoke(bean, args);return invoke;}};return Proxy.newProxyInstance(ProxyBeanPostProcessor.class.getClassLoader(),bean.getClass().getInterfaces(),invocationHandler);}
}
    <!--原始对象--><bean id="userService"  class="com.myspring.factory.UserServiceImpl"/><!--模拟代理1.实现BeanPostProcessor进行加工2.配置文件中对BeanPostProcessor进行配置--><bean id="beanPostProcessor" class="com.myspring.factory.ProxyBeanPostProcessor"/>

六、基于注解的AOP编程

1.基于注解的AOP开发步骤
1.原始对象
2.额外功能
3.切入点
4.组装切面

 #通过切面类  定义了 额外功能@Around定义了切入点@Around("execution(* login(..))")@Aspect 切面类/*1.额外功能public class MyAround implements MethodInterceptor{public Object invoke(MethodInvocation invocation){Object ret = invocation.proceed();return ret;}}2.切入点<aop:config<aop:pointcut id="" expression="execution(* login(..))"/>*/
@Aspect
public class MyAspect {@Around("execution(* login(..))")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("---切面类额外功能");Object proceed = joinPoint.proceed();return proceed;}
}
<!--原始对象--><bean id="userService"  class="com.myspring.aspectproxy.UserServiceImpl"/><!--切面1.额外功能2.切入点3.组装切面--><bean id="arround" class="com.myspring.aspectproxy.MyAspect"/><!--告知Spring基于注解进行AOP编程--><aop:aspectj-autoproxy/>

2.切入点复用
(1)切入点复用

#切入点复用:在切面类中定义一个函数 上面加@Pointcut注解 通过这种方式,定义切入点表达式,后续更加有利于切入点复用。
@Aspect
public class MyAspect { @Pointcut("execution(* login(..))")public void  pointcut(){}@Around(value = "pointcut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("---切面类额外功能111");Object proceed = joinPoint.proceed();return proceed;}@Around(value = "pointcut()")public Object around2(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("---切面类额外功能222");Object proceed = joinPoint.proceed();return proceed;}
}

(2)、动态代理的创建方式

AOP底层实现  2种代理创建方式
1.JDK   通过实现接口 做新的实现类方式 创建代理对象
2.Cglib 通过继承父类 做新的子类  创建代理对象默认情况 AOP编程底层应用JDK动态代理创建方式
如果切换Cglib1.基于注解AOP开发<aop:aspectj-autoproxy proxy-target-class="true"/>2.传统的AOP开发<aop:config proxy-target-class="true"></aop:config>

七、AOP开发中的一个坑

坑:在同一个业务类中,进行业务方法间的相互调用,只有最外层的方法,才是加入了额外功能(内部的方法,通过普通的方式调用,都调用的是原始方法)。如果想让内层的方法也调用代理对象的方法,就要ApplicationContextAware获得工厂,进而获得代理对象。
public class UserServiceImpl implements UserService, ApplicationContextAware {private ApplicationContext ctx;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.ctx = applicationContext;}@Overridepublic void register(User user) {System.out.println("UserServiceImpl.register");/*调用的是原始方法的login方法--->核心功能设计的目的:代理对象的log方法 ——————>额外功能+核心功能ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("/applicationContext2.xml");UserService userService =(UserService) classPathXmlApplicationContext.getBean("userService");userService.login();Spring工厂重量级资源  一个应用中 应该只创建一个工厂*/UserService userService = (UserService) ctx.getBean("userService");userService.login("bugz", "123444");}@Overridepublic void login(String name, String password) {System.out.println("UserServiceImpl.login");}
}

八、AOP阶段知识总结

这波 SpringFramework5.x 我先干了(AOP编程)相关推荐

  1. 树莓派输出pwm波c语言,02树莓派4B—C语言编程——PWM

    01树莓派直接输出PWM波 -- 硬件PWM程序  (推荐使用) #include #include #include //必不可少 int main( void) { int pwm_gpio5 = ...

  2. access求斐波拉契数列_access函数_清华编程高手尹成带你实战C/C++编程_C/C++/C#视频-51CTO学院...

    课程开始让学生了解多平台编程环境的搭建,认识多个操作系统(android,ios,windows,mac os ,linux,unix,ubuntu)并在这些平台上执行c/cpp开发的工具集软件.让单 ...

  3. 第4课 列朋波骨《小学生C++趣味编程》

    #include<iostream> using namespace std; int main() {int i;i=0;i=i+1;i=i+1;i=i+1;i=i+1;i=i+1; c ...

  4. python编程是干嘛的-编程小白必看!Python到底能做什么?

    Python编程语言的入门门槛低,它的可读性强,代码简单易懂,尽管同样是使用C语言编写,但它又摒弃了C语言中复杂的指针,极大程度的简化Python的语法.对于初学者而言,学习Python不仅仅入门容易 ...

  5. 程序设计基础(CC++) 戴波、张东祥 第一章 绪论 编程作业

    21 在屏幕上输出"您好!欢迎来到程序设计世界"(50分) 参考代码 #include <stdio.h> int main(){printf("您好!欢迎来 ...

  6. 小波从此逝,江海寄余生,不但是文坛巨擘还是不世出的编程奇才,王小波离世25周年

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_211 二十五年前的今天,王小波先生因病于北京逝世,享年四十四周岁.喜爱他的人,都知道他是一个特立独行的人,拥有谦虚与自豪并存的强大 ...

  7. 优先队列——斐波那契堆(without source code)

    [0]README 0.1) 本文部分内容转自 数据结构与算法分析,旨在理解 斐波那契堆 的基础知识: 0.2) 文本旨在理清 斐波那契堆的 核心idea,还没有写出源代码实现,表遗憾: 0.3)从实 ...

  8. 斐波那契实现阶乘js_功能与命令式编程。 Java 8中的斐波那契,素数和阶乘

    斐波那契实现阶乘js 有多种编程风格/范例,但是两个著名的风格是Imperative和Functional . 命令式编程是最主要的范例,因为几乎所有主流语言(C ++,Java,C#)都在推广它. ...

  9. c语言---c语言中的斐波那契数列程序

    首先就要先了解何为斐波那契数列---斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故 ...

最新文章

  1. react项目开发步骤_成为专业React开发人员的31个步骤
  2. fedora java 开发环境_Linux(Fedora 14)下 java开发环境配置 ——jdk的安装与配置
  3. html单击按钮时弹出输入框,点击按钮弹出模态框的一系列操作代码实例
  4. 翻转棋游戏c语言讲解,有没有人懂黑白棋(翻转棋)的核心算法
  5. 二次修改:【练习题】构造方法的重载:Vehicles(交通工具)-Car(小汽车)和Truck(卡车)类继承于Vehicles类
  6. ie 浏览器布局中的 offset
  7. 通过NGINX location实现一个域名访问多个项目
  8. WEB交互的划时代革新--HTML5中WebSocket应用【1】
  9. (转)jquery图片左右滚动
  10. 右手螺旋判断磁感应强度方向_弹簧左旋or右旋在功能和应用上有什么区别,如何判断左旋还是右旋...
  11. idea设置主题路径
  12. PID神经网络控制【神经网络二十六】
  13. linux里面rpm是什么文件,linux中deb格式和rpm格式分别是什么?
  14. unity 打包时 StreamingAssets文件的数目过多
  15. VR全景视频、图片播放器
  16. Python 爬楼梯问题--有n阶台阶,上楼可以一步上1阶,2阶,3阶,计算共有多少种不同的走法?
  17. ibm aix_IBM AIX SAN Volume Controller更新和迁移
  18. 用qt合并ts视频文件
  19. Docker配置mc服务器
  20. BMC通过PECI接口获取CPU温度实现方法

热门文章

  1. Photoshop(5)不一样的抠图与字体
  2. 谷歌nexus9刷机_Google推出Nexus One智能手机
  3. Apache Hadoop 基础设施容器化在 Uber 的实践
  4. js 嵌入式开发板_张江镇林志玲教你用JavaScript做嵌入式开发
  5. 【bzoj2563】 阿狸和桃子的游戏 贪心
  6. 【数据库课程设计】SQLServer数据库课程设计(学生宿舍管理),课设报告+源码+数据库关系图
  7. Android蓝牙开发(一)蓝牙模块及核心API
  8. 什么是电压跟随器,它的特点与作用
  9. 关押罪犯(并查集加点问题最详细讲解)
  10. Hive总结 --hive表的创建,删除和修改