框架学习之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];

浙公网安备 33010602011771号