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. C#中的集合类——ArrayList

    1.  ArrayList与数组 数组的长度不可变,元素的类型单一: ArrayList 实际上相当于一个可变长度的动态数组,由于集合中的元素都是object类型,元素的类型可以有多种了:与数组一样, ...

  2. C语言之自增和自减运算符

    一 自增和自减 自增(++):就是给自己的值再加1 自减(--):就是给自己的值减1 tips: ++(--)可以放在前面,也可以放在后面,效果都是一样,都是会给自身+1(-1) 前缀++(--):会 ...

  3. this和$(this)

    this指的是javascript对象而$(this)就是就jquery对象 jQuery.prototype.test=function(){ this.css("color", ...

  4. restful Api 风格契约设计器:Swagger-editor和swagger-ui的应用

    swagger-editor的安装 swagger-editor应用的yaml语法,有定义变量和数据结构,不明白可以参考其示例 安装步骤: 下载swagger-editor git地址 运行npm r ...

  5. 手机无须ROOT不用修改hosts即可在本地测试安卓、苹果APP和H5应用

    开发手机APP和 H5 应用经常需要在本地和线上环境分开测试,一般想到的操作都是修改hosts,我也一直这么干的,但手机上修改hosts是需要 ROOT权限的,这样太过麻烦,还有变砖头的风险,而且有些 ...

  6. 【CSS学习笔记】a标签的四种伪类

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xht ...

  7. 设计模式(二)单例模式Singleton(创建型)

    几乎所有面向对象的程序中,总有一些类的对象需要是唯一的,例如,通过数据库句柄到数据库的连接是独占的.您希望在应用程序中共享数据库句柄,因为在保持连接打开或关闭时,它是一种开销.再如大家最经常用的IM, ...

  8. RelativeLayout各个属性

    android:layout_above="@id/xxx"  --将控件置于给定ID控件之上 android:layout_below="@id/xxx"  ...

  9. js 中的 exec( )方法

    JavaScript exec() 方法 JavaScript RegExp 对象 定义和用法 exec() 方法用于检索字符串中的正则表达式的匹配. 语法:RegExpObject.exec(str ...

  10. HTTP请求返回状态详解

    当用户试图通过 HTTP 访问一台正在运行 Internet 信息服务 (IIS) 的服务器上的内容时,IIS 返回一个表示该请求的状态的数字代码.状态代码可以指明具体请求是否已成功,还可以揭示请求失 ...