反射泛型信息
获取子类传递的泛型信息
public class Demo1 {
public static void main(String[] args) {
new B(); //打印 java.lang.String
new C(); //打印 java.lang.Integer
}
}
class A<T>{
public A(){
//要获取子类传递的泛型信息,要先获取class
Class clazz=this.getClass();
Type type=clazz.getGenericSuperclass(); //获取传递给父类的参数化类型
ParameterizedType ptype=(ParameterizedType) type;//强转一下格式 他就是 A<T>
Type[] types=ptype.getActualTypeArguments(); //获取真实参数数组 就是<>里面的类型,有可能有多个所以是数组
Class c=(Class) types[0];
System.out.println(c.getName());
}
}
class B extends A<String>{
}
class C extends A<Integer>{
}
反射注解
反射注解需要从作用目标上返回
-类上的注解,需要使用Class获取
-方法上的注解,需要Method来获取
-构造器上的注解,需要Construcator来获取
-成员上的注解,需要使用Field来获取
public class Demo2 {
public static void main(String[] args) throws NoSuchMethodException, SecurityException {
//获取作用目标
Class clazz=Test.class;
//获取指定类型的注解,因为可能有多个注解
//获取类上的注解
/* MyAnno myanno=(MyAnno) clazz.getAnnotation(MyAnno.class);
//打印张三 18
System.out.println(myanno.name()+":"+myanno.age()); */
//获取方法上的注解,获取指定方法
Method method=clazz.getMethod("fun");
//获取注解
MyAnno myanno=(MyAnno) method.getAnnotation(MyAnno.class);
//打印李四,36
System.out.println(myanno.name()+":"+myanno.age());
}
}
@MyAnno(name="张三",age=18)
class Test{
@MyAnno(name="李四",age=36)
public void fun(){
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno{
String name();
int age();
}
反射泛型和反射注解的应用案例
我们写一些往数据库添加的操作
public class Test {
private QueryRunner qr=new QueryRunner(JdbcUtils.getDataSource());
public void addUser(User user) throws SQLException{
String sql="";
Object []params={};
qr.update(sql, params);
}
public void addCategory(Category category) throws SQLException{
String sql="";
Object []params={};
qr.update(sql, params);
}
}
我们发现其中很多重复代码,我们就想写一个Basedao
里面有添加和删除的方法,使用了泛型
class BaseDao<T>{
public void add(T bean){
}
public void update(T bean){
}
}
我们只需要继承它,并且给他类型即可
class UserDao extends BaseDao<User>{
public void addUser(User user){
super.add(user);
}
}
为了方便,我们使用泛型的类型作为表名
class BaseDao<T>{
private Class<T> beanclass;
BaseDao(){
//获取泛型的类型
Class clazz=this.getClass();
Type type=clazz.getGenericSuperclass(); //获取传递给父类的参数化类型
ParameterizedType ptype=(ParameterizedType) type;//强转一下格式 他就是 A<T>
Type[] types=ptype.getActualTypeArguments(); //获取真实参数数组 就是<>里面的类型,有可能有多个所以是数组
beanclass=(Class) types[0];
}
public void add(T bean) throws SQLException{
//获取参数的数量,也就是javabean中的属性数量
Field []fs=beanclass.getDeclaredFields();
//我们前面约定过,传递泛型类型即为表名。然后再有几个? 连接几个? 即可
String sql="insert into "+beanclass.getSimpleName()+" values(";
for(int i=0;i<fs.length;i++){
sql+="?";
if(i<fs.length-1){
sql+=",";
}
}
sql+=")";
//参数可以通过注解的方式来获得
Object []params={};
qr.update(sql, params);
}
public void update(T bean){
}
}
动态代理
只学一个方法
方法的作用:在运行时,动态创建一组指定的接口的实现类对象。
比如我们有两个接口
interface A{
}
interface B{
}
我们调用该方法,就可以返回一个实现了这些接口数组的一个对象,这个对象实现了所有接口中的方法
Object o=方法(new Class[]{A.class,B.class})
-----------------------------------------------------------------------
Object proxyObject=Proxy.newProxyInstance(ClassLoader classloader,Class[] interface,InvocationHandler h)
方法的作用:在运行时,动态创建一组指定的接口的实现类对象。
参数:ClassLoader:类加载器,用来将.class文件加载到jvm内存中。这个参数用来将动态生成的类加载到内存中。
Class[] interface:接口数组,生成的类将会实现所有接口的方法
InvocationHandler:调用处理器
例子:
public class Demo3 {
public static void main(String[] args) {
Demo3 d=new Demo3();
ClassLoader classloader=d.getClass().getClassLoader();
//代理对象实现的所有方法都是调用这个接口里面的invoke方法
InvocationHandler h=new InvocationHandler() {
public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {
System.out.println("动态代理");
return null;
}
};
//获取对象
Object o=Proxy.newProxyInstance(classloader, new Class[]{ATest.class, BTest.class},h);
ATest a=(ATest) o;
BTest b=(BTest) o;
o.toString();
a.a();
b.b();
}
}
interface ATest{
public void a();
}
interface BTest{
public void b();
}
我们会神奇的发现竟然输出了三个
hello 动态代理
hello 动态代理
hello 动态代理
这样就确定了InvocationHandler的作用,我们生成的对象实现了所有接口的方法,但是方法内容都是调用InvocationHandler的invoke方法内容
InvocationHandler h=new InvocationHandler() {
public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {
System.out.println("动态代理");
return null;
}
};
我们这里invoke的三个参数 第一个为当前代理对象 例如上面的o,第二个为接口方法 例如 a()方法,第三个为方法参数
Waiter案例
Waiter服务员案例
public interface Waiter {
public void serve();
}
我们一个类实现接口,但是我们需要增强这个类
public class ManWaiter implements Waiter {
public void serve() {
System.out.println("为客户服务");
}
}
public class Demo4 {
public static void main(String[] args) {
Demo4 d=new Demo4();
ClassLoader classloader=d.getClass().getClassLoader();
ManWaiter waiter=new ManWaiter();
InvocationHandler h=new WaiterInvocationHandler(waiter);
Waiter proxywaiter=(Waiter) Proxy.newProxyInstance(classloader, new Class[]{Waiter.class}, h);
//
proxywaiter.serve();
}
}
我们传递一个实现Waiter接口的对象,然后在invoke方法中进行增强,然后我们的代理对象调用方法其实就是调用invoke 就实现了增强
class WaiterInvocationHandler implements InvocationHandler{
private Waiter waiter;
public WaiterInvocationHandler(Waiter waiter){
this.waiter=waiter;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("您好,01号服务员");
waiter.serve();
return null;
}
}
Waiter 被增强对象
代理对象:对对象进行增强
类加载器
作用:将.class文件加载到内存中。
分类:
引导类加载器:用来加载java核心库(jre/lib/rt.jar里的内容)
扩展类加载器:用来加载java的扩展库(jre/lib/ext/*.jar)
应用程序类加载器:用来加载应用下的第三方jar包,还有自己写的类生成的.class文件 (classpath下的类)
分层:
应用程序类加载器的上层是扩展类加载器
扩展类加载器的上层是引导类加载器
类加载器的委托机制
我们自己的项目中定义了一个类A new A()
我们加载这个类A时,先由应用程序类加载器进行加载
但是应用程序会先请求上一级也就是扩展类加载器来加载类A
扩展类加载器接收到以后,也会请求上级引导类加载器来加载类A
引导类加载器会去自己的jar包中寻找A类,如果找到,加载到内存中,返回A对象给扩展类加载器,扩展类再把对象返回给应用程序类加载器
如果没找到,引导类加载器会返回null,然后扩展加载器会去自己的路径下找类A
如果找到,返回对象
没找到就返回null,然后应用程序就在自己的路径下找类A,找到就加载
没找到抛出ClassNotFoundException异常
这样做的好处是安全。比如我们自己定义一个String类,String也是系统类,它会使用委托机制进行加载
最后加载的还是系统的String,我们想替换系统类做一些危险操作,是不可能的
Nginx
Nginx ("engine x") 是一个高性能的HTTP和反向代理服务器。
负载均衡服务器
"负载均衡服务器"是本系统的控制服务器,所有用户的请求都首先到此服务器,然后由此服务器根据各个实际处理服务器状态将请求具体分配到某个实际处理服务器中,对外公开的域名与IP地址都是这台服务器。
负载均衡控制与管理软件安装在这台服务器上,这台服务器一般只做负载均衡任务分配,但不是实际对网络请求进行处理的服务器。
简单说: 当处理高并发时,我们一个服务器处理不了那么多的请求,这时我们会使用多个服务器,但是所有的请求都会发送到负载均衡服务器
然后负载均衡服务器再将请求分配到各个服务器中进行处理。
正向代理和反向代理
正向代理:当我们需要借钱时,一个老板很有钱,我们直接去借,当然失败,但是这时一个朋友是老板的亲戚,我们委托朋友去借。老板并不知道真正借钱的人是谁。这就是正向代理。
反向代理:我们拨打10086,10086会为我们分配一个客服,所有的客服都用10086这个总机号。这个总机号就是反向代理。我们不需要知道谁帮我们完成了请求,只需要拨打这个总机即可。
反向代理的实现
1)需要有一个负载均衡设备来分发用户请求,将用户请求分发到空闲的服务器上
2)服务器返回自己的服务到负载均衡设备
3)负载均衡将服务器的服务返回用
web学到这儿基本也就结束了,很多东西其实边学边忘,只有不断的去学,去练习。
很多笔记也打的非常粗糙,自己还好,估计别人看了也是不知所言。所以一定要加强这一点。
接下来就是框架部分,与大家共勉。
这是最好的时代,也是最坏的时代。但是属于我们的时代。