day23 框架之基础加强

今日任务

aptana(javascript的eclipse插件):http://www.cnblogs.com/terrylin/archive/2012/06/20/2555962.html

jquery技术,查询文档。

  • 今天的总思路:读取配置文件,反射获取类信息,创建对象,监控方法的执行

SSH : struts2 spring hibernate

SSM :springMVC spring Mybaties

spring 核心:IOC——控制反转,创建对象,不再由着程序员,创建对象由spring管理

AOP——面向切面编程,面向整个功能(功能的实现,不止一个类)

  1. 反射技术
  2. 动态代理
  3. 注解技术

注解技术:老程序员看不上,新程序员特别喜欢。

使用配置文件:特别多,特别复杂(新程序员讨厌原因)

注解:简单,方便,内容少。(新程序员特别喜欢) 注解的配置:都在类上或者方法上,代码维护代价高,注解性能问题(老程序员看不上)

课堂笔记

读取配置文件的三种方式

第一种:String realPath = this.getServletContext().getRealPath("/upload");

只能在web工程中使用。

第二种:InputStream in = ClassLoader.getSystemResourceAsStream("peizhi.properties");

使用类加载器读取配置文件的方法(类加载器:加载类的对象),任何工程都可以使用

任何java工程都需要类加载器来,帮助我们加载类,运行,所以任何工程都可以使用类加载器加载配置文件。

ClassLoader是什么:加载类的对象。

第三种:ResourceBundle bundle = ResourceBundle.getBundle("peizhi");

注意:专门用来读取properties文件

演示读取配置文件的方式(第二种和第三种):

准备接口和实现类:

配置文件准备:

思路:

  1. 定义接口
  2. 书写实现类
  3. 定义配置文件

模拟框架开发:接口定义好的,如何知道程序员定义的实现类?

配置文件——定义好了接口的实现类。

通过读取配置文件,可以获取到实现类的全路径,通过反射获取实现类的对象

第二种代码演示:

/**

     * 测试使用类加载器,读取配置文件

     * @throws Exception

     */

    @Test

    public void test1() throws Exception{

        //获取输入流,读取配置文件

        InputStream in = ClassLoader.getSystemResourceAsStream("peizhi.properties");

        //InputStreamReader: 他的构造函数需要InputStream对象,将字节流转换成字符流

        BufferedReader reader = new BufferedReader(new InputStreamReader(in));

        

        String line = null;

        while((line = reader.readLine()) != null){

            System.out.println(line);

        }

    }

效果:

第三种代码演示:

/**

     * 测试使用ResourceBundle,读取配置文件

     * @throws Exception

     */

    @Test

    public void test2() throws Exception{

        //创建对象,读取配置文件

        //ResourceBundle 专门读取properties文件

        ResourceBundle bundle = ResourceBundle.getBundle("peizhi");

        String value = bundle.getString("servlet");

        System.out.println(value);

    }

效果:

注意:任何配置文件,修改过后,都需要重新启动java虚拟机。

原因:读取配置文件的动作只有一次。

如果想要不重新启动java虚拟机,将数据保存在数据库,然后,从数据库获取数据,再进行操作——这样的数据,一般叫做系统变量。

1、反射技术回顾

1.1、Class回顾

Class:相当于工厂在制作产品之前,先设计好的产品图纸。

反射的作用:可以动态的创建某个类的对象,然后动态调用这个类中的成员(方法和属性)。

  1. 对象的getClass方法
  2. 类名.class
  3. Class类forName方法

代码演示:

/**

     * 演示获取Class对象的三种方式

     * @throws ClassNotFoundException

     */

    @Test

    public void test3() throws ClassNotFoundException {

        MyServlet myServlet = new MyServlet();

        System.out.println(myServlet.getClass());

        

        System.out.println(MyServlet.class);

        //clazz:这是一个源远流长的习惯

        //框架经常使用第三种方式

        Class clazz = Class.forName("cn.itcast.web.impl.MyServlet");

        System.out.println(clazz);

}

效果:

1.2、反射类中的成员回顾

第一步:反射类中的构造方法:

通过构造方法,就可以创建类的对象

Class:

Constructor:

/**

     * 演示获取对象的构造方法

     * @throws Exception

     */

    @Test

    public void test4() throws Exception{

        //读取配置文件

        ResourceBundle bundle = ResourceBundle.getBundle("peizhi");

        //获取类全名

        String className = bundle.getString("servlet");

        

        //获取类的构造方法

        Class<?> clazz = Class.forName(className);

        /*Constructor[] constructors = clazz.getConstructors();

        for (Constructor constructor : constructors) {

            System.out.println(constructor);

        }*/

        

        //获取指定的构造方法

        //parameterTypes:给的是构造函数的参数

        Constructor<?> constructor = clazz.getConstructor(null);

        System.out.println(constructor);

        

        Constructor<?> constructor2 = clazz.getConstructor(String.class,String.class);

        System.out.println(constructor2);

        

        //根据构造函数创建对象

        //initargs:构造函数使用需要的参数

        Object newInstance = constructor.newInstance(null);

        System.out.println(newInstance);

        

        Object newInstance2 = constructor2.newInstance("req","res");

        System.out.println(newInstance2);

    }

效果:

反射类中的成员变量:

Class:

/**

     * 演示获取成员变量(属性)

     *

     * @throws Exception

     */

    @Test

    public void test5() throws Exception {

        // 读取配置文件

        ResourceBundle bundle = ResourceBundle.getBundle("peizhi");

        // 获取类全名

        String className = bundle.getString("servlet");

        // 获取Class对象

        Class<?> clazz = Class.forName(className);

        

        Field[] declaredFields = clazz.getDeclaredFields();

        /*for (Field field : declaredFields) {

            System.out.println(field);

        }*/

        Field declaredField = clazz.getDeclaredField("request");

        System.out.println(declaredField);

    }

效果:

反射类中的成员方法:

获取所有方法:

/**

     * 演示获取类中的成员方法

     *

     * @throws Exception

     */

    @Test

    public void test6() throws Exception {

        // 读取配置文件

        ResourceBundle bundle = ResourceBundle.getBundle("peizhi");

        // 获取类全名

        String className = bundle.getString("servlet");

        // 获取Class对象

        Class<?> clazz = Class.forName(className);

        

        Method[] methods = clazz.getMethods();

        for (Method method : methods) {

            System.out.println(method);

        }

        

        System.out.println("================");

        Method method = clazz.getMethod("doGet", java.lang.String.class,java.lang.String.class);

        System.out.println(method);

        System.out.println("==============");

        //演示调用方法obj:调用方法的对象,args:方法的参数

        Object invoke = method.invoke(clazz.newInstance(), "haha","hehe");

        System.out.println(invoke);

    }

效果:

案例:模拟BeanUtils封装数据演示:

思路:

  1. 需要一个封装数据的对象(Person)
  2. 需要一个封装数据的map集合(key值和Person的字段名称一致)
  3. 获取Person的Class对象,只有获取Class对象,才能获取到所有的字段(属性)
  4. 获取所有字段
  5. 循环所有字段和map集合,当key值和字段名称一致,就封装数据

要使用的API:

Class:

Field:

代码演示:

测试类:

/**

     * 演示模拟beanUtils封装数据

     *

     * @throws Exception

     */

    @Test

    public void test7() throws Exception {

        //第一步:创建要被封装数据的对象

        User u = new User();

        System.out.println(u);

        //String:用来保存属性的名称(对应User中的属性)

        //Object:要被封装的数据,任意类型

        Map<String, Object> map = new HashMap<String, Object>();

        map.put("name", "张三");

        map.put("age", 11);

        //封装数据,使用BeanUtils.populate(u, map);

        BeanUtils.populate(u, map);

        System.out.println(u);

    }

工具类:

package cn.itcast.utils;

import java.lang.reflect.Field;

import java.util.Map;

public class BeanUtils {

    public static void populate(Object obj, Map<String, Object> map) {

        //第一步:通过Class对象来获取obj对象中的成员变量

        Class<?> clazz = obj.getClass();

        Field[] declaredFields = clazz.getDeclaredFields();

        //第二步:遍历循环所有的字段,将数据封装进去

        for (Field field : declaredFields) {

            for (String key : map.keySet()) {

                //判断,当前的字段名称是否和map集合中key值,一致,一致,才能封装数据

                if(key.equals(field.getName())){

                    //封装数据

                    //取消访问的检查

                    field.setAccessible(true);

                    try {

                        field.set(obj, map.get(key));

                    } catch (Exception e) {

                        e.printStackTrace();

                    }

                }

            }

        }

    }

}

效果:

2、动态代理

2.1、动态代理介绍

struts2 、 hibernate 底层使用的动态代理。

Spring 在AOP当中,使用了大量的动态代理,JDK自带的接口代理(有接口才能代理),子类代理(cglib代理)

动态代理:访问被代理的类,进行拦截,处理,处理完了,放行

代理设计模式:

注意:以上还只是代理设计模式,怎么变成动态代理?上面的故事,如果改成,看到姐姐之后,直接上帝创建了妹妹,就是动态代理。

2.2、动态代理演示

1、先获取创建代理对象的类,调用它的方法,创建出一个代理对象

2、代理对象具体要做什么事情(代理策略),需要设置

创建代理类的对象:

创建代理对象的方法:

代理策略对象:

代理策略方法:

需求和步骤(模拟框架读取配置文件,创建代理对象,并调用接口方法):

  1. 读取配置文件
  2. 获取类全名
  3. 反射获取Class对象
  4. 获取当前类接口(根据接口做代理)

  5. 创建代理类(Proxy)
  6. 代理策略:监控方法执行
  7. 获取代理类的接口方法,调用执行

代码演示:

/**

     * 演示动态代理

     */

    @Test

    public void test8()throws Exception{

        //1)    读取配置文件

        ResourceBundle bundle = ResourceBundle.getBundle("peizhi");

        //2)    获取类全名

        String className = bundle.getString("servlet");

        //3)    反射获取Class对象

        final Class<?> clazz = Class.forName(className);

        

        //4)    获取当前类接口(根据接口做代理)

        Class<?>[] interfaces = clazz.getInterfaces();

        //以上都是反射操作

        //5)    创建代理类(Proxy),设置了代理的策略

        Object obj = Proxy.newProxyInstance(clazz.getClassLoader(), interfaces, new InvocationHandler() {

            

            @Override

            public Object invoke(Object proxy, Method method, Object[] args)

                    throws Throwable {

                //6)    代理策略:监控方法执行

                //method 当前被调用的方法

                //args 是调用方法时候的参数

                System.out.println("======方法启动=====");

                System.out.println("method:"+method);

                for (Object dd : args) {

                    System.out.println(dd);

                }

                //method是一个方法对象,可以调用它的invoke方法,让他去执行

                if(method.getName().equals("doGet")){

                    

                    Object invoke = method.invoke(clazz.newInstance(), args);

                }

                System.out.println("======执行完成=====");

                return null;

            }

        });

        

        //7)    获取代理类的接口方法,调用执行

        //通过接口数组的第一个接口,获取第一个接口中的所有方法

        Method[] methods = interfaces[0].getMethods();

        //通过操作methods方法数组,获取第一个方法对象,通过他的invoke方法,调用方法执行

        methods[0].invoke(obj, "req","res");

    }

    

    //为什么要用动态代理?

    //1)可以通过代理对象,对指定的类的方法进行修改(拦截或者增强),使用动态代理修改类,不需要修改原来的代码,因为我们是创建一个新的类

    //2)一次动态代理,可以对当前指定的类,的所有方法,进行拦截或者增强的操作

    

    /**

     * 继承

     * 当你要写的这个类,与原来要被增强的那个类是同一类型事物(animal cat dog)

     *

     * 装饰设计模式

     * 当你要写的这个类,与原来要被增强的那个类不是同一类型事物(animal dianziGou / 对request对象进行增强,也是使用装饰设计模式)

     *

     * 动态代理

     * 需要,在java虚拟机启动之后,再去修改指定的类,那么就使用动态代理

     *

     * 怎么就突然出现了一个类呢?

     * Person.java -->javac命令 Person.class

     * 创建代理类,底层机制类似javac命令,所以不属于java范畴,后期,入职sun公司,请回来告诉我。

     *

     * */

总结:

使用动态代理中,可以一个类的方法执行前后做增强和过滤的动作

2.3、动态代理完成全站乱码处理

过滤器:全站乱码过滤器

需求:使用动态代理方式,处理乱码

  1. 过滤器:对请求进行增强
  2. 过滤器:过滤任务写在doFilter方法
  3. 过滤任务:通过创建代理对象来增强原来的request
  4. 根据不同请求方式处理:
  5. Post:setCharacterEncoding("utf-8")'
  6. Get:根据不同的方法,不同处理
  7. getParameter方法:new String();
  8. getParameterValues方法:遍历循环,new String();
  9. getParameterMap:循环遍历,new String();
  10. request对象还要其他方法,其他方法执行不做任何处理

package cn.itcast.filter;

import java.io.IOException;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

import java.util.Map;

import java.util.Set;

import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

public class EncodingFilter2 implements Filter {

    @Override

    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override

    public void doFilter(ServletRequest request, ServletResponse response,

            FilterChain chain) throws IOException, ServletException {

        final HttpServletRequest req = (HttpServletRequest) request;

        HttpServletResponse res = (HttpServletResponse) response;

        res.setContentType("text/html;charset=utf-8");

        // 使用动态代理创建代理对象,对request进行增强

        HttpServletRequest myrequest = (HttpServletRequest) Proxy

                .newProxyInstance(req.getClass().getClassLoader(), req

                        .getClass().getInterfaces(), new InvocationHandler() {

                    @Override

                    public Object invoke(Object proxy, Method method,

                            Object[] args) throws Throwable {

                        // 设置代理策略,对request的获取数据的方法进行增强

                        //获取请求方式

                        String method2 = req.getMethod();

                        if(method2.equalsIgnoreCase("post")){

                            req.setCharacterEncoding("utf-8");

                            return method.invoke(req, args);

                        }else if(method2.equalsIgnoreCase("get")){

                            //获取请求参数的方法

                            //根据不同的方法,进行不同增强操作

                            if("getParameter".equals(method.getName())){

                                String parameter = req.getParameter((String)args[0]);

                                if(parameter != null){

                                    parameter = new String(parameter.getBytes("iso-8859-1"),"utf-8");

                                }

                                return parameter;

                            }else if("getParameterValues".equals(method.getName())){

                                

                                String[] values = req.getParameterValues((String)args[0]);

                                if(values != null){

                                    for (int i = 0; i < values.length; i++) {

                                        values[i] = new String(values[i].getBytes("iso-8859-1"),"utf-8");

                                    }

                                }

                                return values;

                            }else if("getParameterMap".equals(method.getName())){

                                Map<String, String[]> map = req.getParameterMap();

                                if(map != null){

                                    Set<String> keySet = map.keySet();

                                    for (String key : keySet) {

                                        String[] values = map.get(key);

                                        for (int i = 0; i < values.length; i++) {

                                            values[i] = new String(values[i].getBytes("iso-8859-1"),"utf-8");

                                        }

                                    }

                                }

                                return map;

                            }else{

                                return method.invoke(req, args);

                            }

                        }else{

                            return method.invoke(req, args);

                        }

                    }

                });

        chain.doFilter(myrequest, res);

    }

    @Override

    public void destroy() {

    }

}

3、注解技术

3.1、注解和注释区别

注释:它是对程序中的代码进行解释说明。注释是给人看。

注解:它是给程序使用的。在程序运行的时候(编译的时候),会根据相应的注解,然后完成对应的操作。注解经常需要和反射一起使用。

早期的程序:

基本是程序配合配置文件一起工作,在程序运行的时候,会读取配置文件中的数据。

现在程序:

在程序运行的时候,不再使用配置文件(少量使用配置文件),而是在程序加入注解来代替配置文件。

3.2、注解格式和JDK注解简单演示

注解的格式:@注解的名称( key=value , key=value, key=value。。。。。。 )

JDK中自带的3个注解:

1、方法复写的时候注解:

使用Override注解声明当前方法是复写父类的方法,或者是实现了接口中的方法

jdk1.5@override不支持接口的方法复写,1.6以上可以

2、过时的方法注解:

@Deprecated它声明某个方法已经过时。

3、消除程序中的警告

@SuppressWarnings 消除警告。

3.3、自己定义注解的实现

自己定义注解:

格式:public @interface 注解名字{

定义注解的成员变量;

}

第一步:

效果:

自定义注解:

自定义注解使用:

3.4、注解的细节

@Test注解不能出现在类上:

获取Junit源代码:

第一步:找到junit在eclipse中的位置

第二步:使用反编译神器,将class文件还原成.java文件

发现:在@Test注解的底层类上有两个注解

@Retention(RetentionPolicy.RUNTIME)

指定注解什么时候存在

@Target({java.lang.annotation.ElementType.METHOD})

指定注解可以写在什么位置

1、在定义注解的时候,可以指定注解什么时候存在——@Retention

这个注解是存在于源代码上,还是编译之后的class文件上,还是运行时期也要存在。

@Retention 使用jdk中的Retention 来声明自己的注解将来在程序中存活的具体时间

RetentionPolicy:声明注解存活的时间:

代码演示:

注意:声明注解的存活时间时,使用runtime是给反射程序使用的。

2、在定义注解的时候,指定注解可以写在什么位置——@Target

注解是使用在类上,方法上,构造方法上,成员变量,或者是其他注解上。

在Java中提供的@Target注解,声明自己 定义的注解在其他的类中的存在位置。

代码演示:

效果:

演示代码(反射获取注解):

@Test

    @MyAnnotation

    public void test9() throws Exception{

        

        Method method = this.getClass().getMethod("test9", null);

        MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);

        System.out.println(annotation);

    }

效果:

  1. 在注解中定义成员变量

    格式:数据类型 变量名() default 默认值

    测试代码:

效果:

3.5、使用注解完成数据库连接的获取

定义注解:

package cn.itcast.zhujie;

import java.lang.annotation.Retention;

import java.lang.annotation.Target;

import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)

@Target({java.lang.annotation.ElementType.METHOD})

public @interface MyAnnotation {

    String driverClass();

    String jdbcUrl();

    String user();

    String password();

}

使用注解:

package cn.itcast.test;

import java.lang.annotation.Annotation;

import java.lang.reflect.Method;

import java.sql.Connection;

import java.sql.DriverManager;

import org.junit.Test;

import cn.itcast.zhujie.MyAnnotation;

public class TestUtils2 {

    @MyAnnotation(driverClass="com.mysql.jdbc.Driver",jdbcUrl="jdbc:mysql:///day14",user="root",password="root")

    @Test

    public void test() throws Exception{

        //获取注解上的值,获取数据库连接

        Method method = this.getClass().getMethod("test", null);

        MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);

        String driverClass = annotation.driverClass();

        String jdbcUrl = annotation.jdbcUrl();

        String user = annotation.user();

        String password = annotation.password();

        

        Class.forName(driverClass);

        

        Connection connection = DriverManager.getConnection(jdbcUrl, user, password);

        System.out.println(connection);

        

    }

}

day23 框架之基础加强的更多相关文章

  1. ABP框架实践基础篇之开发UI层

    返回总目录<一步一步使用ABP框架搭建正式项目系列教程> 说明 其实最开始写的,就是这个ABP框架实践基础篇.在写这篇博客之前,又回头复习了一下ABP框架的理论,如果你还没学习,请查看AB ...

  2. 关于Yii框架的基础知识

    第一次写博文,也不知道怎么写,不太熟悉,带小伙伴学习一样我日常使用的Yii框架. PHP中的开发框架有很多,比如:ThinkPHP.Yii.CI.Laravel.Phalcon等.现在流行度最高的是L ...

  3. 一个标准的,兼容性很好的div仿框架的基础模型!

    <!DOCTYPE html> <html > <head> <meta http-equiv="Content-Type" conten ...

  4. Java学习关于集合框架的基础接口--Collection接口

     集合框架(Collection  Framework)是Java最强大的子系统之一,位于java.util 包中.集合框架是一个复杂的接口与和类层次,提供了管理对象组的最新技术.Java集合框架标准 ...

  5. 整合SSM框架必备基础—SpringMVC(下)

    在上一篇文章<整合SSM框架必备基础-SpringMVC(上)>中,胖达介绍了关于SpringMVC的诞生.优势以及执行流程等理论知识点,这篇文章打算在实操中加深一下对SpringMVC的 ...

  6. [LINQ2Dapper]最完整Dapper To Linq框架(一)---基础查询

    此例子是使用LINQ2Dapper封装,效率优于EntityFramwork,并且支持.NetFramework和.NetCore框架,只依赖于Dapper 支持.net framework4.5.1 ...

  7. 手撸ORM浅谈ORM框架之基础篇

    好奇害死猫 一直觉得ORM框架好用.功能强大集众多优点于一身,当然ORM并非完美无缺,任何事物优缺点并存!我曾一度认为以为使用了ORM框架根本不需要关注Sql语句如何执行的,更不用关心优化的问题!!! ...

  8. spring+springMVC+mybatis的框架项目基础环境搭建

    上一个项目在后台用到spring+springMVC+mybatis的框架,先新项目初步需求也已经下来,不出意外的话,应该也是用这个框架组合. 虽然在之前activiti相关的学习中所用到的框架也是这 ...

  9. python 网络框架twisted基础学习及详细讲解

    twisted网络框架的三个基础模块:Protocol, ProtocolFactory, Transport.这三个模块是构成twisted服务器端与客户端程序的基本.Protocol:Protoc ...

随机推荐

  1. HDU--1006

    题目介绍 Problem Description The three hands of the clock are rotating every second and meeting each oth ...

  2. Vmware Vcenter6.0 全新安装及群集配置介绍

    介绍如何安装vsphere ESxi主机及将vmware vsphere5.5升级到vmware vsphere6.0的介绍,而今天呢,主要介绍vsphere vcenter,说到vsphere vc ...

  3. Java Web学习笔记--JSP for循环

    JSP for循环 <%@ page language="java" contentType="text/html; charset=UTF-8" %&g ...

  4. 【转】Hive执行计划

    执行语句 hive> explain select s.id, s.name from student s left outer join student_tmp st on s.name = ...

  5. find指令

    1.命令格式 find path -options [-print -exec -ok ...] 2.命令功能 查找文件,并作出相应处理 3.命令参数

  6. PDF转换成Txt

    我的弱智想法是所有能转换成PDF的文件,就都用PDF预览,上传成功后开启一个线程把文档转换成PDF,PDF再转换成txt. 目的是把txt插入索引进行全文检索. 调用的时候 string filePa ...

  7. Lua 中的string库(字符串函数库)总结

    (字符串函数库)总结 投稿:junjie 字体:[增加 减小] 类型:转载 时间:2014-11-20我要评论 这篇文章主要介绍了Lua中的string库(字符串函数库)总结,本文讲解了string库 ...

  8. GIT 代码管理工具 SourceTree

    什么是git? git是一款开源的分布式版本控制工具 在世界上所有的分布式版本控制工具中,git是最快.最简单.最流行的 git的起源 作者是Linux之父:Linus Benedict Torval ...

  9. Unity3d请求webservice

    我们在对接第三方sdk时,第三方sdk通常会以一个webservice接口的形式供我们来调用.而这些接口会以提供我们get,post,soap等协议来进行访问.get,post方法相信大家都比较熟悉了 ...

  10. Python将列表中的string元素进行类型转换

    例如 将 a=['1','2.0','3L'] 转换为 a=[1,2.0,3L] 只需 map(eval,['1','2.0','3L']) 即可 eval(expression[, globals[ ...