动静代理

  • 代理对象存在的价值:次要用于拦挡对实在业务对象的拜访。
  • 代理对象有什么办法?
  • 当初要生成某一个对象的代理对象,这个代理对象通常也要编写一个来生成,所以首先要编写用于生成代理对象的类。
  • 如何编写生成代理对象的类,两个因素:
  • 代理谁
  • 如何生成代理对象
  • 代理谁?
  • 设计一个类变量,以及一个构造函数,记住代理类 代理哪个对象。
  • 如何生成代理对象?
  • 设计一个办法生成代理对象(在办法内编写代码生成代理对象是此处编程的难点)
  • Java提供了一个Proxy类,调用它的newInstance办法能够生成某个对象的代理对象,应用该办法生成代理对象时,须要三个参数:
  • 1.生成代理对象应用哪个类装载器
  • 2.生成哪个对象的代理对象,通过接口指定
  • 3.生成的代理对象的办法里干什么事,由开发人员编写handler接口的实现来指定。
  • 初学者必须必须记住的2件事件:
  • Proxy类负责创立代理对象时,如果指定了handler(处理器),那么不论用户调用代理对象的什么办法,该办法都是调用处理器的invoke办法。
  • 因为invoke办法被调用须要三个参数:代理对象、办法、办法的参数,因而不论代理对象哪个办法调用处理器的invoke办法,都必须把本人所在的对象、本人(调用invoke办法的办法)、办法的参数传递进来。

代理模式

  • 代理模式作用:
  • 屏蔽实在行为的拜访,让程序更加平安。
  • 能够对实在行为的调用进行管制。
  • 通过一个案例:来阐明代理的实现以及代理的作用
  • 代理模式实现:
  • 1.代理类与被代理类要实现同一个接口.
//潘金莲 ---被代理

public class Pjl implements KindWoman{

    public void throwEye(){

        System.out.println("潘金莲抛媚眼");

    }

    public void doSomething(){

        System.out.println("潘金莲。。。。。。。。");

    }

}

//王婆 ---代理

public class Wp implements KindWoman {

    private KindWoman woman;

    public Wp(KindWoman woman) {

        this.woman = woman;

    }

    public void throwEye() {

        woman.throwEye();

    }

    public void doSomething() {

        woman.doSomething();

    }

}

  • 2.在代理类中持有被代理对象.
public class Xmq {

    public static void main(String[] args) {

        KindWoman woman = new Pjl();

        Wp wp = new Wp(woman);

        wp.throwEye();//实在执行的是潘金莲,然而咱们看不到,所以屏蔽了实在行为。

    }

}

  • 3.在代理类中调用被代理的行为。
    public void throwEye() {

        //在这里做操作,能够管制是否调用实在行为。

        woman.throwEye();

        //在这个地位,能够在实在行为调用实现后,在做操作。

    }

    public void doSomething() {

        woman.doSomething();

    }

}

AOP:面向切面的编程

  • AOP的底层实现就是通过动静代理来做到的。
  • 动静代理
  • 在代理模式根底上倒退的,它不在是对繁多的类型进行代理,而是能够对任意的一个实现了接口的类的对象做代理。

动静代理实现

  • 两种形式:
  • 这种形式要求,被代理类必须实现接口,即只能为接口做代理.
  • 1.通过jdk中提供的Proxy类来实现
  • 2.通过cglib来实现,它不要求实现接口。
  • 第一种形式的代码实现:
  • loader: 要求,传递的是被代理类类加载器ClassLoader
  • interfaces: 要求:失去被代理对象所实现的接口的所有Class对象
  • h: 它的类型是InvocationHandler,这是一个接口
  • 失去其Class对象,在Class类中提供一个办法getClassLoader();
  • 类加载器怎么获取:
  • 失去其Class对象,在Class类中提供一个办法 getInterfaces();它返回的是Class[],就代表所实现接口的所有Class对象。
  • 怎么获取所有实现接口的Class对象?
  • InvocationHandler 是代理实例的调用处理程序 实现的接口。
  • Proxy类中有一个办法newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h);
  • 参数:
  • InvocationHandler接口中有一个办法invoke;
  • public Object invoke(Object proxy, Method method, Object[] args);
  • 参数 proxy 就是代理对象
  • 参数 method 就是调用办法
  • 参数 args 就是调用的办法的参数
  • 返回值,就是实在行为执行后返回的后果,会传递给代理对象调用的办法.
  • eg:
public class Student implements Person {

    public String say(String message) {

        return "hello " + message;

    }

}

public class StudentProxyTest {

    public static void main(String[] args) {

        // 做Person接口实现类Student的动静代理。

        // 1.创立一个Student 被代理

        final Person s = new Student();

        // 2.失去s的代理对象.

        Person sproxy = (Person) Proxy.newProxyInstance(s.getClass()

                .getClassLoader(), s.getClass().getInterfaces(),

                new InvocationHandler() {

                    // 参数 proxy就是代理对象

                    // 参数method就是调用办法

                    // 参数args就是调用的办法的参数

                    // 返回值,就是实在行为执行后返回的后果,会传递给代理对象调用的办法.

                    public Object invoke(Object proxy, Method method,

                            Object[] args) throws Throwable {

                        // proxy,就是代理对象,咱们个别不应用。

                        // method,就是要拜访的办法。

                        // args 就是要拜访的办法的参数

                        return method.invoke(s, args); // s.say("james");

                    }

                });

        String message = sproxy.say("james"); // 这个是代理对象调用say办法.

        System.out.println(message);

    }

}

动静代理案例1—实现编码过滤

public class LoginServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        String username = request.getParameter("username");

        System.out.println(username);

    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        doGet(request, response);

    }

}

  • 2.操作
public class EncodingFilter implements Filter {

    public void init(FilterConfig filterConfig) throws ServletException {

    }

    public void doFilter(ServletRequest request, ServletResponse response,

            FilterChain chain) throws IOException, ServletException {

        // 1.强转

        final HttpServletRequest req = (HttpServletRequest) request;

        HttpServletResponse resp = (HttpServletResponse) response;

        // 2.操作

        // 创立一个req对象的代理对象reqProxy

        HttpServletRequest reqProxy = (HttpServletRequest) Proxy

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

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

                    public Object invoke(Object proxy, Method method,

                            Object[] args) throws Throwable {

                        // 1.失去办法名称

                        String methodName = method.getName();

                        if ("getParameter".equals(methodName)) {

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

                            return new String(param.getBytes("iso8859-1"),

                                    "utf-8");

                        } else {

                            // 不是getParameter办法,就执行其原来操作.

                            return method.invoke(req, args);

                        }

                    }

                });

        // 3.放行

        chain.doFilter(reqProxy, resp);

    }

    public void destroy() {

    }

}

动静代理案例2–细粒度的权限管制

  • 数据库
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);

  • 代码实现:
  • 1.实现登录操作,将user存储到session中.
  • login.jsp LoginServlet UserService UserDao.
  • 2.登录胜利,跳转到book.jsp页面。
  • 能够通过在申请,携带参数来判断要做什么操作
  • 在这个页面上有四个超连贯,拜访的是同一个servlet(BookServlet)
  • 问题:怎么让一个servlet解决多个申请?
book add


book update


book delete


book search

  • 在servlet中判断method值是什么,调用不同的申请解决办法.
  • 这种形式下,在做权限管制时,如果应用url级别权限管制,就不能通过判断申请的资源门路来解决。
  • 能够应用细粒度权限管制:
  • 实现原理:应用注解+动静代理来实现。
  • 注解:它用于定义以后行为的拜访须要什么权限。
  • 动静代理帮忙咱们实现管制拦挡。简略说,就是在代理中,会判断以后用户是否具备拜访该行为的权限,如果有会调用被代理的行为,如果没有,不调用行为,间接抛出权限有余。
  • 3.实现权限管制
  • 1.创立一个BookInfo注解,它是用于形容行为拜访时,须要什么权限的.
    @Retention(RetentionPolicy.RUNTIME)

    @Target(ElementType.METHOD)

    @Inherited

    public @interface BookInfo {

    String value(); //这就是权限名称

    }

2.在BookServiceFactory中进行权限管制

  • 1.失去以后行为拜访须要的权限名称
  • BookInfo bif = method.getAnnotation(BookInfo.class);
  • String pname = bif.value();
  • 2.失去以后登录的用户
  • User user = (User) args[0];
  • 咱们在所有的service的办法上增加了一个User参数。
  • 那么咱们获取时,就能够间接通过invoke办法的args参数获取.
  • 1.首先判断用户是否存在,也就是判断它是否登录了。

    User user = (User) args[0];

    if (user == null) {

        throw new RuntimeException("没有登录,请登录后操作");

    }

  • 2.如果登录了,依据用户查询数据库,失去这个用户所具备的所有权限名称

    * 应用ColumnListHandler进行封装查问后果。

SELECT 

    privileges.name 

FROM 

    users,PRIVILEGES,userprivilege 

WHERE 

    users.id=userprivilege.user_id 

AND 

    privileges.id=userprivilege.privilege_id 

AND 

    users.id=?";

QueryRunner runner = new QueryRunner(DataSourceUtils

        .getDataSource());

List<Object> pnames = runner.query(sql,

        new ColumnListHandler(), user.getId());

  1. 判断用户是否具备权限
                // 实在行为拜访前--判断用户是否有权限执行以后行为

                boolean flag = method.isAnnotationPresent(BookInfo.class);

                if (!flag) {

                    // 不须要权限

                    return method.invoke(service, args);

                }

if (pnames.contains(pname)) {

                    Object obj = method.invoke(service, args);

                    // 实在行为拜访 后

                    return obj;

                } else {

                    throw new RuntimeException("权限有余");

类加载器

  • 什么是类加载器,有什么作用?
  • 1.疏导类加载器 BootStrap jre/lib/rt.jar
  • 2.扩大类加载器 ExtClassLoader JRE/lib/ext/*.jar
  • 3.利用类加载器(零碎类加载器) AppClassLoader SystemClassLoader CLASSPATH指定的所有jar或目录
  • 类加载器的作用就是将java中的字节码文件(.class文件)转换成Class对象。
  • 当 JVM 启动时,会造成由三个类加载器组成的初始类加载器层次结构:
  • 在java中ClassLoader代表类加载器,所有的类加载器都是ClassLoader的子.
  • bootstrap classloader:疏导(也称为原始)类加载器,它负责加载Java的外围类。这个加载器的是十分非凡的,它实际上不是 java.lang.ClassLoader的子类,而是由JVM本身实现的。能够通过执行以下代码来取得bootstrap classloader加载了那些外围类库:
URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs();

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

  System.out.println(urls[i].toExternalForm());

}

  • 因为JVM在启动的时候就主动加载它们,所以不须要在零碎属性CLASSPATH中指定这些类库
  • 演示类加载器
  • 在Class类中有一个办法 getClassLoader()它返回的就是一个类加载器.
  • 问题:类加载器如果获取?
  • 1.获取疏导类加载器
  • ClassLoader cl = String.class.getClassLoader();
  • System.out.println(cl);
  • 后果是null.
  • 起因:疏导类加载器非凡,它基本就不是java实现。所有在失去疏导类回载器是后果就是null.
  • 2.扩大类加载器
  • ClassLoader cl = AccessBridge.class.getClassLoader();
  • System.out.println(cl); //sun.misc.Launcher$ExtClassLoader@9cb0f4
  • 3.利用类加载器
  • ClassLoader cl = this.getClass().getClassLoader();
  • System.out.println(cl); //sun.misc.Launcher$AppClassLoader@164dbd5

全盘负责委托机制

  • 全盘负责:即是当一个classloader加载一个Class的时候,这个Class所依赖的和援用的其它Class通常也由这个classloader负责载入。
  • 委托机制:先让parent(父)类加载器 寻找,只有在parent找不到的时候才从本人的类门路中去寻找。
  • 类加载还采纳了cache机制:如果 cache中保留了这个Class就间接返回它,如果没有才从文件中读取和转换成Class,并存入cache,这就是为什么批改了Class然而必须重新启动JVM能力失效,并且类只加载一次的起因。

自定义类加载器

  • 创立了一个类 javax.activation.MimeType,在这个类中有一个办法show();当jvm加载这个类时,因为在rt.jar包下也存在一个MimeType类,并且包名都一样,这时jvm就会应用疏导类加载器加载这个类,而咱们想得到的其实是应该由利用类加载器加载的Class.
  • 解决方案:自定义类加载器.
  • 1.创立一个类,去继承自ClassLoader
  • 2.重写findClass办法,在这个办法中通过defineClass将一个.class文件转换成Class对象.

泛型反射

====动静代理

  • 代理对象存在的价值:次要用于拦挡对实在业务对象的拜访。
  • 代理对象有什么办法?
  • 当初要生成某一个对象的代理对象,这个代理对象通常也要编写一个来生成,所以首先要编写用于生成代理对象的类。
  • 如何编写生成代理对象的类,两个因素:
  • 代理谁
  • 如何生成代理对象
  • 代理谁?
  • 设计一个类变量,以及一个构造函数,记住代理类 代理哪个对象。
  • 如何生成代理对象?
  • 设计一个办法生成代理对象(在办法内编写代码生成代理对象是此处编程的难点)
  • Java提供了一个Proxy类,调用它的newInstance办法能够生成某个对象的代理对象,应用该办法生成代理对象时,须要三个参数:
  • 1.生成代理对象应用哪个类装载器
  • 2.生成哪个对象的代理对象,通过接口指定
  • 3.生成的代理对象的办法里干什么事,由开发人员编写handler接口的实现来指定。
  • 初学者必须必须记住的2件事件:
  • Proxy类负责创立代理对象时,如果指定了handler(处理器),那么不论用户调用代理对象的什么办法,该办法都是调用处理器的invoke办法。
  • 因为invoke办法被调用须要三个参数:代理对象、办法、办法的参数,因而不论代理对象哪个办法调用处理器的invoke办法,都必须把本人所在的对象、本人(调用invoke办法的办法)、办法的参数传递进来。

代理模式

  • 代理模式作用:
  • 屏蔽实在行为的拜访,让程序更加平安。
  • 能够对实在行为的调用进行管制。
  • 通过一个案例:来阐明代理的实现以及代理的作用
  • 代理模式实现:
  • 1.代理类与被代理类要实现同一个接口.
//潘金莲 ---被代理

public class Pjl implements KindWoman{

    public void throwEye(){

        System.out.println("潘金莲抛媚眼");

    }

    public void doSomething(){

        System.out.println("潘金莲。。。。。。。。");

    }

}

//王婆 ---代理

public class Wp implements KindWoman {

    private KindWoman woman;

    public Wp(KindWoman woman) {

        this.woman = woman;

    }

    public void throwEye() {

        woman.throwEye();

    }

    public void doSomething() {

        woman.doSomething();

    }

}

  • 2.在代理类中持有被代理对象.
public class Xmq {

    public static void main(String[] args) {

        KindWoman woman = new Pjl();

        Wp wp = new Wp(woman);

        wp.throwEye();//实在执行的是潘金莲,然而咱们看不到,所以屏蔽了实在行为。

    }

}

  • 3.在代理类中调用被代理的行为。
    public void throwEye() {

        //在这里做操作,能够管制是否调用实在行为。

        woman.throwEye();

        //在这个地位,能够在实在行为调用实现后,在做操作。

    }

    public void doSomething() {

        woman.doSomething();

    }

}

AOP:面向切面的编程

  • AOP的底层实现就是通过动静代理来做到的。
  • 动静代理
  • 在代理模式根底上倒退的,它不在是对繁多的类型进行代理,而是能够对任意的一个实现了接口的类的对象做代理。

动静代理实现

  • 两种形式:
  • 这种形式要求,被代理类必须实现接口,即只能为接口做代理.
  • 1.通过jdk中提供的Proxy类来实现
  • 2.通过cglib来实现,它不要求实现接口。
  • 第一种形式的代码实现:
  • loader: 要求,传递的是被代理类类加载器ClassLoader
  • interfaces: 要求:失去被代理对象所实现的接口的所有Class对象
  • h: 它的类型是InvocationHandler,这是一个接口
  • 失去其Class对象,在Class类中提供一个办法getClassLoader();
  • 类加载器怎么获取:
  • 失去其Class对象,在Class类中提供一个办法 getInterfaces();它返回的是Class[],就代表所实现接口的所有Class对象。
  • 怎么获取所有实现接口的Class对象?
  • InvocationHandler 是代理实例的调用处理程序 实现的接口。
  • Proxy类中有一个办法newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h);
  • 参数:
  • InvocationHandler接口中有一个办法invoke;
  • public Object invoke(Object proxy, Method method, Object[] args);
  • 参数 proxy 就是代理对象
  • 参数 method 就是调用办法
  • 参数 args 就是调用的办法的参数
  • 返回值,就是实在行为执行后返回的后果,会传递给代理对象调用的办法.
  • eg:
public class Student implements Person {

    public String say(String message) {

        return "hello " + message;

    }

}

public class StudentProxyTest {

    public static void main(String[] args) {

        // 做Person接口实现类Student的动静代理。

        // 1.创立一个Student 被代理

        final Person s = new Student();

        // 2.失去s的代理对象.

        Person sproxy = (Person) Proxy.newProxyInstance(s.getClass()

                .getClassLoader(), s.getClass().getInterfaces(),

                new InvocationHandler() {

                    // 参数 proxy就是代理对象

                    // 参数method就是调用办法

                    // 参数args就是调用的办法的参数

                    // 返回值,就是实在行为执行后返回的后果,会传递给代理对象调用的办法.

                    public Object invoke(Object proxy, Method method,

                            Object[] args) throws Throwable {

                        // proxy,就是代理对象,咱们个别不应用。

                        // method,就是要拜访的办法。

                        // args 就是要拜访的办法的参数

                        return method.invoke(s, args); // s.say("james");

                    }

                });

        String message = sproxy.say("james"); // 这个是代理对象调用say办法.

        System.out.println(message);

    }

}

动静代理案例1—实现编码过滤

public class LoginServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        String username = request.getParameter("username");

        System.out.println(username);

    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        doGet(request, response);

    }

}

  • 2.操作
public class EncodingFilter implements Filter {

    public void init(FilterConfig filterConfig) throws ServletException {

    }

    public void doFilter(ServletRequest request, ServletResponse response,

            FilterChain chain) throws IOException, ServletException {

        // 1.强转

        final HttpServletRequest req = (HttpServletRequest) request;

        HttpServletResponse resp = (HttpServletResponse) response;

        // 2.操作

        // 创立一个req对象的代理对象reqProxy

        HttpServletRequest reqProxy = (HttpServletRequest) Proxy

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

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

                    public Object invoke(Object proxy, Method method,

                            Object[] args) throws Throwable {

                        // 1.失去办法名称

                        String methodName = method.getName();

                        if ("getParameter".equals(methodName)) {

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

                            return new String(param.getBytes("iso8859-1"),

                                    "utf-8");

                        } else {

                            // 不是getParameter办法,就执行其原来操作.

                            return method.invoke(req, args);

                        }

                    }

                });

        // 3.放行

        chain.doFilter(reqProxy, resp);

    }

    public void destroy() {

    }

}

动静代理案例2–细粒度的权限管制

  • 数据库
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);

  • 代码实现:
  • 1.实现登录操作,将user存储到session中.
  • login.jsp LoginServlet UserService UserDao.
  • 2.登录胜利,跳转到book.jsp页面。
  • 能够通过在申请,携带参数来判断要做什么操作
  • 在这个页面上有四个超连贯,拜访的是同一个servlet(BookServlet)
  • 问题:怎么让一个servlet解决多个申请?
book add


book update


book delete


book search

  • 在servlet中判断method值是什么,调用不同的申请解决办法.
  • 这种形式下,在做权限管制时,如果应用url级别权限管制,就不能通过判断申请的资源门路来解决。
  • 能够应用细粒度权限管制:
  • 实现原理:应用注解+动静代理来实现。
  • 注解:它用于定义以后行为的拜访须要什么权限。
  • 动静代理帮忙咱们实现管制拦挡。简略说,就是在代理中,会判断以后用户是否具备拜访该行为的权限,如果有会调用被代理的行为,如果没有,不调用行为,间接抛出权限有余。
  • 3.实现权限管制
  • 1.创立一个BookInfo注解,它是用于形容行为拜访时,须要什么权限的.
    @Retention(RetentionPolicy.RUNTIME)

    @Target(ElementType.METHOD)

    @Inherited

    public @interface BookInfo {

    String value(); //这就是权限名称

    }

2.在BookServiceFactory中进行权限管制

  • 1.失去以后行为拜访须要的权限名称
  • BookInfo bif = method.getAnnotation(BookInfo.class);
  • String pname = bif.value();
  • 2.失去以后登录的用户
  • User user = (User) args[0];
  • 咱们在所有的service的办法上增加了一个User参数。
  • 那么咱们获取时,就能够间接通过invoke办法的args参数获取.
  • 1.首先判断用户是否存在,也就是判断它是否登录了。

    User user = (User) args[0];

    if (user == null) {

        throw new RuntimeException("没有登录,请登录后操作");

    }

  • 2.如果登录了,依据用户查询数据库,失去这个用户所具备的所有权限名称

    * 应用ColumnListHandler进行封装查问后果。

SELECT 

    privileges.name 

FROM 

    users,PRIVILEGES,userprivilege 

WHERE 

    users.id=userprivilege.user_id 

AND 

    privileges.id=userprivilege.privilege_id 

AND 

    users.id=?";

QueryRunner runner = new QueryRunner(DataSourceUtils

        .getDataSource());

List<Object> pnames = runner.query(sql,

        new ColumnListHandler(), user.getId());

  1. 判断用户是否具备权限
                // 实在行为拜访前--判断用户是否有权限执行以后行为

                boolean flag = method.isAnnotationPresent(BookInfo.class);

                if (!flag) {

                    // 不须要权限

                    return method.invoke(service, args);

                }

if (pnames.contains(pname)) {

                    Object obj = method.invoke(service, args);

                    // 实在行为拜访 后

                    return obj;

                } else {

                    throw new RuntimeException("权限有余");

类加载器

  • 什么是类加载器,有什么作用?
  • 1.疏导类加载器 BootStrap jre/lib/rt.jar
  • 2.扩大类加载器 ExtClassLoader JRE/lib/ext/*.jar
  • 3.利用类加载器(零碎类加载器) AppClassLoader SystemClassLoader CLASSPATH指定的所有jar或目录
  • 类加载器的作用就是将java中的字节码文件(.class文件)转换成Class对象。
  • 当 JVM 启动时,会造成由三个类加载器组成的初始类加载器层次结构:
  • 在java中ClassLoader代表类加载器,所有的类加载器都是ClassLoader的子.
  • bootstrap classloader:疏导(也称为原始)类加载器,它负责加载Java的外围类。这个加载器的是十分非凡的,它实际上不是 java.lang.ClassLoader的子类,而是由JVM本身实现的。能够通过执行以下代码来取得bootstrap classloader加载了那些外围类库:
URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs();

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

  System.out.println(urls[i].toExternalForm());

}

  • 因为JVM在启动的时候就主动加载它们,所以不须要在零碎属性CLASSPATH中指定这些类库
  • 演示类加载器
  • 在Class类中有一个办法 getClassLoader()它返回的就是一个类加载器.
  • 问题:类加载器如果获取?
  • 1.获取疏导类加载器
  • ClassLoader cl = String.class.getClassLoader();
  • System.out.println(cl);
  • 后果是null.
  • 起因:疏导类加载器非凡,它基本就不是java实现。所有在失去疏导类回载器是后果就是null.
  • 2.扩大类加载器
  • ClassLoader cl = AccessBridge.class.getClassLoader();
  • System.out.println(cl); //sun.misc.Launcher$ExtClassLoader@9cb0f4
  • 3.利用类加载器
  • ClassLoader cl = this.getClass().getClassLoader();
  • System.out.println(cl); //sun.misc.Launcher$AppClassLoader@164dbd5

全盘负责委托机制

  • 全盘负责:即是当一个classloader加载一个Class的时候,这个Class所依赖的和援用的其它Class通常也由这个classloader负责载入。
  • 委托机制:先让parent(父)类加载器 寻找,只有在parent找不到的时候才从本人的类门路中去寻找。
  • 类加载还采纳了cache机制:如果 cache中保留了这个Class就间接返回它,如果没有才从文件中读取和转换成Class,并存入cache,这就是为什么批改了Class然而必须重新启动JVM能力失效,并且类只加载一次的起因。

自定义类加载器

  • 创立了一个类 javax.activation.MimeType,在这个类中有一个办法show();当jvm加载这个类时,因为在rt.jar包下也存在一个MimeType类,并且包名都一样,这时jvm就会应用疏导类加载器加载这个类,而咱们想得到的其实是应该由利用类加载器加载的Class.
  • 解决方案:自定义类加载器.
  • 1.创立一个类,去继承自ClassLoader
  • 2.重写findClass办法,在这个办法中通过defineClass将一个.class文件转换成Class对象.

泛型反射

  • 问题:在BaseDaoImpl类动静代理

====

  • 代理对象存在的价值:次要用于拦挡对实在业务对象的拜访。
  • 代理对象有什么办法?
  • 当初要生成某一个对象的代理对象,这个代理对象通常也要编写一个来生成,所以首先要编写用于生成代理对象的类。
  • 如何编写生成代理对象的类,两个因素:
  • 代理谁
  • 如何生成代理对象
  • 代理谁?
  • 设计一个类变量,以及一个构造函数,记住代理类 代理哪个对象。
  • 如何生成代理对象?
  • 设计一个办法生成代理对象(在办法内编写代码生成代理对象是此处编程的难点)
  • Java提供了一个Proxy类,调用它的newInstance办法能够生成某个对象的代理对象,应用该办法生成代理对象时,须要三个参数:
  • 1.生成代理对象应用哪个类装载器
  • 2.生成哪个对象的代理对象,通过接口指定
  • 3.生成的代理对象的办法里干什么事,由开发人员编写handler接口的实现来指定。
  • 初学者必须必须记住的2件事件:
  • Proxy类负责创立代理对象时,如果指定了handler(处理器),那么不论用户调用代理对象的什么办法,该办法都是调用处理器的invoke办法。
  • 因为invoke办法被调用须要三个参数:代理对象、办法、办法的参数,因而不论代理对象哪个办法调用处理器的invoke办法,都必须把本人所在的对象、本人(调用invoke办法的办法)、办法的参数传递进来。

代理模式

  • 代理模式作用:
  • 屏蔽实在行为的拜访,让程序更加平安。
  • 能够对实在行为的调用进行管制。
  • 通过一个案例:来阐明代理的实现以及代理的作用
  • 代理模式实现:
  • 1.代理类与被代理类要实现同一个接口.
//潘金莲 ---被代理

public class Pjl implements KindWoman{

    public void throwEye(){

        System.out.println("潘金莲抛媚眼");

    }

    public void doSomething(){

        System.out.println("潘金莲。。。。。。。。");

    }

}

//王婆 ---代理

public class Wp implements KindWoman {

    private KindWoman woman;

    public Wp(KindWoman woman) {

        this.woman = woman;

    }

    public void throwEye() {

        woman.throwEye();

    }

    public void doSomething() {

        woman.doSomething();

    }

}

  • 2.在代理类中持有被代理对象.
public class Xmq {

    public static void main(String[] args) {

        KindWoman woman = new Pjl();

        Wp wp = new Wp(woman);

        wp.throwEye();//实在执行的是潘金莲,然而咱们看不到,所以屏蔽了实在行为。

    }

}

  • 3.在代理类中调用被代理的行为。
    public void throwEye() {

        //在这里做操作,能够管制是否调用实在行为。

        woman.throwEye();

        //在这个地位,能够在实在行为调用实现后,在做操作。

    }

    public void doSomething() {

        woman.doSomething();

    }

}

AOP:面向切面的编程

  • AOP的底层实现就是通过动静代理来做到的。
  • 动静代理
  • 在代理模式根底上倒退的,它不在是对繁多的类型进行代理,而是能够对任意的一个实现了接口的类的对象做代理。

动静代理实现

  • 两种形式:
  • 这种形式要求,被代理类必须实现接口,即只能为接口做代理.
  • 1.通过jdk中提供的Proxy类来实现
  • 2.通过cglib来实现,它不要求实现接口。
  • 第一种形式的代码实现:
  • loader: 要求,传递的是被代理类类加载器ClassLoader
  • interfaces: 要求:失去被代理对象所实现的接口的所有Class对象
  • h: 它的类型是InvocationHandler,这是一个接口
  • 失去其Class对象,在Class类中提供一个办法getClassLoader();
  • 类加载器怎么获取:
  • 失去其Class对象,在Class类中提供一个办法 getInterfaces();它返回的是Class[],就代表所实现接口的所有Class对象。
  • 怎么获取所有实现接口的Class对象?
  • InvocationHandler 是代理实例的调用处理程序 实现的接口。
  • Proxy类中有一个办法newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h);
  • 参数:
  • InvocationHandler接口中有一个办法invoke;
  • public Object invoke(Object proxy, Method method, Object[] args);
  • 参数 proxy 就是代理对象
  • 参数 method 就是调用办法
  • 参数 args 就是调用的办法的参数
  • 返回值,就是实在行为执行后返回的后果,会传递给代理对象调用的办法.
  • eg:
public class Student implements Person {

    public String say(String message) {

        return "hello " + message;

    }

}

public class StudentProxyTest {

    public static void main(String[] args) {

        // 做Person接口实现类Student的动静代理。

        // 1.创立一个Student 被代理

        final Person s = new Student();

        // 2.失去s的代理对象.

        Person sproxy = (Person) Proxy.newProxyInstance(s.getClass()

                .getClassLoader(), s.getClass().getInterfaces(),

                new InvocationHandler() {

                    // 参数 proxy就是代理对象

                    // 参数method就是调用办法

                    // 参数args就是调用的办法的参数

                    // 返回值,就是实在行为执行后返回的后果,会传递给代理对象调用的办法.

                    public Object invoke(Object proxy, Method method,

                            Object[] args) throws Throwable {

                        // proxy,就是代理对象,咱们个别不应用。

                        // method,就是要拜访的办法。

                        // args 就是要拜访的办法的参数

                        return method.invoke(s, args); // s.say("james");

                    }

                });

        String message = sproxy.say("james"); // 这个是代理对象调用say办法.

        System.out.println(message);

    }

}

动静代理案例1—实现编码过滤

public class LoginServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        String username = request.getParameter("username");

        System.out.println(username);

    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        doGet(request, response);

    }

}

  • 2.操作
public class EncodingFilter implements Filter {

    public void init(FilterConfig filterConfig) throws ServletException {

    }

    public void doFilter(ServletRequest request, ServletResponse response,

            FilterChain chain) throws IOException, ServletException {

        // 1.强转

        final HttpServletRequest req = (HttpServletRequest) request;

        HttpServletResponse resp = (HttpServletResponse) response;

        // 2.操作

        // 创立一个req对象的代理对象reqProxy

        HttpServletRequest reqProxy = (HttpServletRequest) Proxy

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

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

                    public Object invoke(Object proxy, Method method,

                            Object[] args) throws Throwable {

                        // 1.失去办法名称

                        String methodName = method.getName();

                        if ("getParameter".equals(methodName)) {

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

                            return new String(param.getBytes("iso8859-1"),

                                    "utf-8");

                        } else {

                            // 不是getParameter办法,就执行其原来操作.

                            return method.invoke(req, args);

                        }

                    }

                });

        // 3.放行

        chain.doFilter(reqProxy, resp);

    }

    public void destroy() {

    }

}

动静代理案例2–细粒度的权限管制

  • 数据库
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);

  • 代码实现:
  • 1.实现登录操作,将user存储到session中.
  • login.jsp LoginServlet UserService UserDao.
  • 2.登录胜利,跳转到book.jsp页面。
  • 能够通过在申请,携带参数来判断要做什么操作
  • 在这个页面上有四个超连贯,拜访的是同一个servlet(BookServlet)
  • 问题:怎么让一个servlet解决多个申请?
book add


book update


book delete


book search

  • 在servlet中判断method值是什么,调用不同的申请解决办法.
  • 这种形式下,在做权限管制时,如果应用url级别权限管制,就不能通过判断申请的资源门路来解决。
  • 能够应用细粒度权限管制:
  • 实现原理:应用注解+动静代理来实现。
  • 注解:它用于定义以后行为的拜访须要什么权限。
  • 动静代理帮忙咱们实现管制拦挡。简略说,就是在代理中,会判断以后用户是否具备拜访该行为的权限,如果有会调用被代理的行为,如果没有,不调用行为,间接抛出权限有余。
  • 3.实现权限管制
  • 1.创立一个BookInfo注解,它是用于形容行为拜访时,须要什么权限的.
    @Retention(RetentionPolicy.RUNTIME)

    @Target(ElementType.METHOD)

    @Inherited

    public @interface BookInfo {

    String value(); //这就是权限名称

    }

2.在BookServiceFactory中进行权限管制

  • 1.失去以后行为拜访须要的权限名称
  • BookInfo bif = method.getAnnotation(BookInfo.class);
  • String pname = bif.value();
  • 2.失去以后登录的用户
  • User user = (User) args[0];
  • 咱们在所有的service的办法上增加了一个User参数。
  • 那么咱们获取时,就能够间接通过invoke办法的args参数获取.
  • 1.首先判断用户是否存在,也就是判断它是否登录了。

    User user = (User) args[0];

    if (user == null) {

        throw new RuntimeException("没有登录,请登录后操作");

    }

  • 2.如果登录了,依据用户查询数据库,失去这个用户所具备的所有权限名称

    * 应用ColumnListHandler进行封装查问后果。

SELECT 

    privileges.name 

FROM 

    users,PRIVILEGES,userprivilege 

WHERE 

    users.id=userprivilege.user_id 

AND 

    privileges.id=userprivilege.privilege_id 

AND 

    users.id=?";

QueryRunner runner = new QueryRunner(DataSourceUtils

        .getDataSource());

List<Object> pnames = runner.query(sql,

        new ColumnListHandler(), user.getId());

  1. 判断用户是否具备权限
                // 实在行为拜访前--判断用户是否有权限执行以后行为

                boolean flag = method.isAnnotationPresent(BookInfo.class);

                if (!flag) {

                    // 不须要权限

                    return method.invoke(service, args);

                }

if (pnames.contains(pname)) {

                    Object obj = method.invoke(service, args);

                    // 实在行为拜访 后

                    return obj;

                } else {

                    throw new RuntimeException("权限有余");

类加载器

  • 什么是类加载器,有什么作用?
  • 1.疏导类加载器 BootStrap jre/lib/rt.jar
  • 2.扩大类加载器 ExtClassLoader JRE/lib/ext/*.jar
  • 3.利用类加载器(零碎类加载器) AppClassLoader SystemClassLoader CLASSPATH指定的所有jar或目录
  • 类加载器的作用就是将java中的字节码文件(.class文件)转换成Class对象。
  • 当 JVM 启动时,会造成由三个类加载器组成的初始类加载器层次结构:
  • 在java中ClassLoader代表类加载器,所有的类加载器都是ClassLoader的子.
  • bootstrap classloader:疏导(也称为原始)类加载器,它负责加载Java的外围类。这个加载器的是十分非凡的,它实际上不是 java.lang.ClassLoader的子类,而是由JVM本身实现的。能够通过执行以下代码来取得bootstrap classloader加载了那些外围类库:
URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs();

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

  System.out.println(urls[i].toExternalForm());

}

  • 因为JVM在启动的时候就主动加载它们,所以不须要在零碎属性CLASSPATH中指定这些类库
  • 演示类加载器
  • 在Class类中有一个办法 getClassLoader()它返回的就是一个类加载器.
  • 问题:类加载器如果获取?
  • 1.获取疏导类加载器
  • ClassLoader cl = String.class.getClassLoader();
  • System.out.println(cl);
  • 后果是null.
  • 起因:疏导类加载器非凡,它基本就不是java实现。所有在失去疏导类回载器是后果就是null.
  • 2.扩大类加载器
  • ClassLoader cl = AccessBridge.class.getClassLoader();
  • System.out.println(cl); //sun.misc.Launcher$ExtClassLoader@9cb0f4
  • 3.利用类加载器
  • ClassLoader cl = this.getClass().getClassLoader();
  • System.out.println(cl); //sun.misc.Launcher$AppClassLoader@164dbd5

全盘负责委托机制

  • 全盘负责:即是当一个classloader加载一个Class的时候,这个Class所依赖的和援用的其它Class通常也由这个classloader负责载入。
  • 委托机制:先让parent(父)类加载器 寻找,只有在parent找不到的时候才从本人的类门路中去寻找。
  • 类加载还采纳了cache机制:如果 cache中保留了这个Class就间接返回它,如果没有才从文件中读取和转换成Class,并存入cache,这就是为什么批改了Class然而必须重新启动JVM能力失效,并且类只加载一次的起因。

自定义类加载器

  • 创立了一个类 javax.activation.MimeType,在这个类中有一个办法show();当jvm加载这个类时,因为在rt.jar包下也存在一个MimeType类,并且包名都一样,这时jvm就会应用疏导类加载器加载这个类,而咱们想得到的其实是应该由利用类加载器加载的Class.
  • 解决方案:自定义类加载器.
  • 1.创立一个类,去继承自ClassLoader
  • 2.重写findClass办法,在这个办法中通过defineClass将一个.class文件转换成Class对象.

泛型反射

  • 问题:在BaseDaoImpl类中须要失去以后这个类上的泛型的Class对象,而间接通过T.class这是不对的.
  • 怎么失去以后这个类上的泛型的Class?
  • Type type = this.getClass().getGenericSuperclass(); // 失去以后类上的泛型–父类型
  • Type[] params = ((ParameterizedType) type).getActualTypeArguments(); // 失去以后类上所有的泛型类型Class
  • clazz = (Class) params[0];中须要失去以后这个类上的泛型的Class对象,而间接通过T.class这是不对的.
  • 怎么失去以后这个类上的泛型的Class?
  • Type type = this.getClass().getGenericSuperclass(); // 失去以后类上的泛型–父类型
  • Type[] params = ((ParameterizedType) type).getActualTypeArguments(); // 失去以后类上所有的泛型类型Class
  • clazz = (Class) params[0];
  • 问题:在BaseDaoImpl类中须要失去以后这个类上的泛型的Class对象,而间接通过T.class这是不对的.
  • 怎么失去以后这个类上的泛型的Class?
  • Type type = this.getClass().getGenericSuperclass(); // 失去以后类上的泛型–父类型
  • Type[] params = ((ParameterizedType) type).getActualTypeArguments(); // 失去以后类上所有的泛型类型Class
  • clazz = (Class) params[0];