框架学习之java基础加强

框架学习之java基础加强

注解

注解作用:取代传统配置文件,通知编译器、虚拟机 该Java程序如何运行 。

* 区分注解 和 注释 区别? 注释 给程序员阅读代码说明 ,注解给 虚拟机读取 关于类如何运行信息

 

典型应用:使用注解取代配置文件,采用反射技术读取注解的信息

JDK自带三个注解的使用

java5.0 程序允许使用注解技术 -------  @interface

JDK中自带三个 最基本注解

@Override :表示该方法是对父类方法覆盖 ------ 编译时检查是否构成覆盖  (从JDK6.0开始,可以用于方法实现)

@Deprecated :用于方法过时声明 ----- 考虑原来API被新的API取代,或者某些方法存在安全问题,声明该方法已经过时

@SuppressWarnings :用于在类编译时,忽略警告信息

自定义注解与应用

注解的应用编程

1、注解类定义

2、在目标类应用注解 ---- 重点

3、通过反射技术,获取注解信息,控制目标类如何运行

 

1、注解类定义

使用@interface 定义

属性语法: 返回值 名称() default 默认值 ;

 

注意:

属性的类型 String、基本数据类型、枚举、Class 、其它注解类型、以上数据类型相应一维数组

特殊属性value, 如果一个注解只有一个属性value ,在使用该注解时,省略value=

 

元注解:注解的注解,在自定义注解时,应用这些元注解来修饰 自定义注解类

@Retention : 指定注解信息在哪个阶段存在 Source Class Runtime

@Target : 指定注解修饰目标对象类型  TYPE 类、接口  FIELD 成员变量 METHOD 方法

 

@Documented :使用该元注解修饰,该注解的信息可以生成到javadoc 文档中

@Inherited :如果一个注解使用该元注解修改,应用注解目标类的子类都会自动继承该注解

 

***** @Retention @Target 是自定义注解必须使用两个元注解

示例1 银行最大转帐金额

1) 使用properties配置最大转账金额

2) 使用注解取代配置文件

1) 定义银行信息注解 BankInfo

@Retention(RetentionPolicy.RUNTIME)

// 运行时使用

@Target(ElementType.METHOD)

public @interface BankInfo {

       // 最大转账金额

       double maxTransferMoney();

}

 

2) 在目标程序中应用注解

@BankInfo(maxTransferMoney = 50000)

public void transfer(String inAccount, String outAccount, double money) {

...

}

 

3) 在程序运行时,通过反射技术获取注解的信息

java.lang.reflect.AnnotatedElement 提供获取注解的方法

       getAnnotation(Class<T> annotationClass)  获取指定注解的信息

       isAnnotationPresent(Class<? extends Annotation> annotationClass)  判断该对象上是否存在目标注解

 

反射 Class、Constructor、Field、Method 都实现了该接口

 

步骤一:获得注解修饰目标对象对应反射对象 (Class、Constructor、Field、Method )

步骤二:判断目标对象上是否存在该注解 isAnnotationPresent(Class<? extends Annotation> annotationClass)

步骤三:获得该注解信息 getAnnotation(Class<T> annotationClass)

 

配置文件 配置信息很灵活进行修改,为什么还需要注解技术呢?

最早:没有配置文件,数据在程序代码中,不方便修改

后来:通过配置文件,将动态数据提取到配置文件中,方便修改

再后来:随着系统业务越来越复杂,配置文件大小越来越大,使用配置文件最大缺点代码可读性变差、配置文件过大,维护及其不便 ,注解的出现简化配置文件维护不便、可读性差问题。

示例2 JDBC连接参数注解

create table products(

   id int primary key auto_increment,

   name varchar(40),

   price double

);

 

insert into products values(null,'冰箱',3000);

insert into products values(null,'洗衣机',2000);

insert into products values(null,'电视',5000);

 

将数据库驱动导入工程

 

注解定义

在目标类或者方法上应用注解

通过反射在运行时读取注解信息

 

Servlet3.0特性

注解配置

注解技术产生JDK5.0 例如:@override , 在实际开发中注解经常用来取代配置文件

 

<servlet>

   <servlet-name>

   <serlvet-class>

</servlet>

 

<servlet-mapping>

   <servlet-name>

   <url-pattern>

</servlet-mapping>

 

使用@WebServlet取代  : @WebServlet(value="/hello")

@WebFilter 取代过滤器配置 : @WebFilter(value="/hello")

@WebListener 取代监听器配置 : @WebListener

 

@WebInitParam 为Servlet和Filter传递初始化参数

 

***** 注解不能取代web.xml 所有功能 , 必须配置welcome-file 、error-page

****** metadata-complete  web-app元素的属性

设置为true 将不支持注解技术

不设置 或者 设置为false 将支持注解 技术

异步支持

步骤一 对Servlet或者Filter 添加异步支持 asyncSupported=true

步骤二 开启异步线程

AsyncContext asyncContext = request.startAsync();

new Thread(new Executor(asyncContext)).start();

 

* 通过 AsyncContext  对象获得 request response servletcontext

 

通过

AsyncContext ctx = req.startAsync();

ctx.addListener(new AsyncListener() {

    public void onComplete(AsyncEvent asyncEvent) throws IOException {

        // 做一些清理工作或者其他

    }

    ...

});

文件上传支持

在Servlet3.0之前 编写文件上传 :需要 jsp-smartupload 、commons-fileupload  第三方jar包

从Servlet3.0之后,Servlet规程中内置 文件上传 API支持

 

1、提供@MultipartConfig ,如果一个Servlet 使用该注解,在Servlet中解析request请求时,将根据multipart/form-data 格式进行解析

* 默认 按照urlencoded 格式解析

 

2、使用 request.getParameter 获得普通表单域内容

* 从Servlet3.0开始可以 使用getParameter 获得上传表单中 普通字段值

* 乱码解除 request.setCharacterEncoding

 

3、获得文件上传域信息 使用Part类

request.setCharacterEncoding  解决上传文件名乱码问题

 

*** 注意getParameter使用 必须在 getPart 之前,文件乱码处理才会生效

 

动态代理

动态代理 可以拦截对真实业务对象的访问

 

注意:

1、代理对象需要和真实业务对象 提供相同行为方法

2、代理对象 拦截真实对象访问(阻止)、修改真实对象访问参数、修改真实对象操作返回值

 

代理原理:程序中获得真实业务对象,通过真实业务对象生成代理对象,通过代理对象间接访问真实业务对象 

* 代理对象 阻止访问、修改参数和返回值 

 

开发步骤

1、使用Java中动态代理,必须存在接口

Proxy类,通过真实业务对象ClassLoader 和 真实业务对象 实现Interface ,在内存中虚拟一个代理类对象

 

2、使用Proxy类,根据真实业务对象 生成代理对象

newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

 

3、实现invoke 方法

不改变原来代码逻辑 : return method.invoke(liudehua, args); // liudehua 真实业务对象

阻止目标访问、修改参数和返回值

if(method.getName().equals("xxx方法")){

  // 再对xxx方法 进行增强 改动

}

 

***** invoke方法中会操作真实业务对象 ,通常不会使用proxy对象

 

动态代理、包装、继承 都是Java中 方法增强的手段 --------------- 动态代理和包装 灵活性要比继承 更好

示例1

web工程中请求参数乱码处理

示例2

基于动态代理和注解 实现权限管理 系统模型

1、系统存在若干功能, 将功能需要权限 定义注解

2、在业务层操作类 上面添加这些注解信息

3、web层调用业务层,通过动态代理技术,获得注解信息 ,判断用户是否具有相应权限

 

create table users(

  id int primary key auto_increment,

  username varchar(40),

  password varchar(40)

);

 

insert into users values(null,'aaa','111');

insert into users values(null,'bbb','111');

insert into users values(null,'ccc','111');

 

 

create table privileges(

   id int primary key auto_increment,

   name varchar(40)

);

 

insert into privileges values(null,'添加图书');

insert into privileges values(null,'修改图书');

insert into privileges values(null,'查看图书');

insert into privileges values(null,'删除图书');

 

多对多表关系

create table userprivilege(

   user_id int ,

   privilege_id int,

   foreign key(user_id) references users(id),

   foreign key(privilege_id) references privileges(id),

   primary key(user_id,privilege_id)

);

 

insert into userprivilege values(1,1);

 

book.jsp 点击图书四个功能 --- 调用BookService中相应四个方法执行

 

4) 完成登录功能  ---- 将登陆信息保存session

5) 将权限信息 定义为注解 对象,修饰BookService

6) 提供工厂类, 将接口和实现类 进行解耦合 ---- 在Servlet不需要知道实现类具体实现

 

BookService bookService = new BookServiceImpl(); ========= > BookService bookService = BookFactory.getBookService();

 

7) 动态代理中,根据用户查询具有所有权限

select privileges.name from privileges,userprivilege where privileges.id = userprivilege.privilege_id and userprivilege.user_id = ?;

类加载器

类加载器(也是java程序),负责读取.class字节码文件,将文件内容加载到内存中,生成Class 类对象

Hello.java ---- Hello.class ------ Class对象 Hello

 

JVM类加载器初始化层次结构

1、BootStrap 引导类加载器 ----- JRE/lib/rt.jar 及其它该目录jar包

2、ExtClassLoader 扩展类加载器 ---- JRE/lib/ext/*.jar

3、AppClassLoader 应用类加载器 ---- 加载当前工程classpath 下jar包 WEB-INF/lib 、WEB-INF/classes

 

4、自定义类加载器 ,加载特殊指定目录类

 

* 所有类加载器都是 java.lang.ClassLoader 子类 (BootStrap 加载器除外 ,该加载器是用 C语言实现的)

 

类加载器: 全盘负责委托机制 

1、全盘负责:即是当一个classloader加载一个Class的时候,这个Class所依赖的和引用的其它Class通常也由这个classloader负责载入。(防止一个类被多个加载器加载)

2、委托机制:先让parent(父)类加载器 寻找,只有在parent找不到的时候才从自己的类路径中去寻找

 

实验:

javax.activation.MimeType 存在rt.jar --------- BootStrap

 

demo4 编译没错,运行有错

 

demo5

java.lang.ClassCastException: javax.activation.MimeType cannot be cast to javax.activation.MimeType

* 两个不同加载器 加载同一个类之后,会生成两个Class类对象,不能转换

 

结论:

1、JVM中加载器采用全盘负责委托机制

2、同一个类 被不同加载器加载后,会生成不同Class对象

3、了解 自定义类加载器

 

泛型反射

Type type = this.getClass().getGenericSuperclass(); // 得到当前类上的泛型--父类型

 

Type[] params = ((ParameterizedType) type).getActualTypeArguments(); // 得到当前类上所有的泛型类型Class

 

clazz = (Class) params[0];     

posted @ 2017-11-12 11:26  Nevada  阅读(566)  评论(0)    收藏  举报