文档版本 | 开发工具 | 测试平台 | 工程名字 | 日期 | 作者 | 备注 |
---|---|---|---|---|---|---|
V1.0 | 2016.06.17 | lutianfei | none |
代理对象存在的价值:主要用于拦截对真实业务对象的访问。
代理对象有什么方法?
如何编写生成代理对象的类,两个要素:
代理谁?
如何生成代理对象?
Java提供了一个Proxy类,调用它的newInstance方法可以生成某个对象的代理对象,使用该方法生成代理对象时,需要三个参数:
初学者必须必须记住的2件事情:
代理模式作用:
通过一个案例:来说明代理的实现以及代理的作用
代理模式实现:
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();
}
}
public class Xmq {
public static void main(String[] args) {
KindWoman woman = new Pjl();
Wp wp = new Wp(woman);
wp.throwEye();//真实执行的是潘金莲,但是我们看不到,所以屏蔽了真实行为。
}
}
public void throwEye() {
//在这里做操作,可以控制是否调用真实行为。
woman.throwEye();
//在这个位置,可以在真实行为调用完成后,在做操作。
}
public void doSomething() {
woman.doSomething();
}
}
AOP的底层实现就是通过动态代理来做到的。
动态代理
两种方式:
第一种方式的代码实现:
loader
: 要求,传递的是被代理类的类加载器ClassLoader interfaces
: 要求:得到被代理对象所实现的接口的所有Class对象。 h
: 它的类型是InvocationHandler,这是一个接口。 InvocationHandler**接口中有一个方法**invoke;
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);
}
}
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);
}
}
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() {
}
}
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中.
2.登录成功,跳转到book.jsp页面。
<a href="${pageContext.request.contextPath}/book?method=add">book adda>
<br>
<a href="${pageContext.request.contextPath}/book?method=update">book updatea>
<br>
<a href="${pageContext.request.contextPath}/book?method=delete">book deletea>
<br>
<a href="${pageContext.request.contextPath}/book?method=search">book searcha>
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface BookInfo {
String value(); //这就是权限名称
}
2.在BookServiceFactory中进行权限控制
2.得到当前登录的用户
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());
// 真实行为访问前--判断用户是否有权限执行当前行为
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("权限不足");
什么是类加载器,有什么作用?
BootStrap
jre/lib/rt.jar
ExtClassLoader
JRE/lib/ext/*.jar
AppClassLoader
SystemClassLoader CLASSPATH指定的所有jar或目录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());
}
演示类加载器
1.获取引导类加载器
2.扩展类加载器
3.应用类加载器
创建了一个类 javax.activation.MimeType,在这个类中有一个方法show();当jvm加载这个类时,因为在rt.jar包下也存在一个MimeType类,并且包名都一样,这时jvm就会使用引导类加载器加载这个类,而我们想得到的其实是应该由应用类加载器加载的Class.
解决方案:自定义类加载器.
问题:在BaseDaoImpl类中需要得到当前这个类上的泛型的Class对象,而直接通过T.class这是不对的.
怎样得到当前这个类上的泛型的Class?