1.反射是什么?
程序运行时,通过类名能够获得类的属性和方法。使用方式如下
获取到clazz以后 就能通过clazz获取其他属性和方法。
2.反射的原理
Object 类(所有类都继承这个类) 其中有个方法 public final Class getClass()
所有的子类都继承了这个方法,返回了一个Class类;这个Class类中包含了某个类的属性、方法、和构造器等;对应的是一个加载到 JVM的中的一个.class 文件
正常方式:
引入类名称----------》通过这个类名去new一个对象----------------》取得实例化对象
反射:
取得实例化对象------------------》getClass()方法----------------------》得到完整的“包类”名称
所有被创建的类 都被放到一个Class类中
获取反射对象 只有一个地址,一个类被加载,
3.怎么使用反射?
反射在Spring IOC和AOP中的应用
ioc是一种思想 叫做控制反转,也就是说把对象创建的主动权 new一个对象 从 用户手中交给了IOC容器去管理,当一个对象需要一些外部资源的时候,IOC容器帮助我们注入这些所依赖的对象!
ioc=工厂模式+反射+文件属性
根据配置文件,应用程序在运行时依赖IoC容器来动态注入对象需要的外部资源。默认是无参构造
不用反射机制的工厂模式
/**
* 工厂模式
*/
interface fruit{
public abstract void eat();
}
class Apple implements fruit{
public void eat(){
System.out.println("Apple");
}
}
class Orange implements fruit{
public void eat(){
System.out.println("Orange");
}
}
// 构造工厂类
// 也就是说以后如果我们在添加其他的实例的时候只需要修改工厂类就行了
class Factory{
public static fruit getInstance(String fruitName){
fruit f=null;
if("Apple".equals(fruitName)){
f=new Apple();
}
if("Orange".equals(fruitName)){
f=new Orange();
}
return f;
}
}
class hello{
public static void main(String[] a){
fruit f=Factory.getInstance("Orange");
f.eat();
}
}
利用反射机制的工厂模式
interface fruit{
public abstract void eat();
}
class Apple implements fruit{
public void eat(){
System.out.println("Apple");
}
}
class Orange implements fruit{
public void eat(){
System.out.println("Orange");
}
}
class Factory{
public static fruit getInstance(String ClassName){
fruit f=null;
try{
f=(fruit)Class.forName(ClassName).newInstance();
}catch (Exception e) {
e.printStackTrace();
}
return f;
}
}
class hello{
public static void main(String[] a){
fruit f=Factory.getInstance("Reflect.Apple");
if(f!=null){
f.eat();
}
}
}
利用反射,只要传入类名,就可以获取实力类,我们怎么知道包和类名呢?通过一个配置文件
apple=xxxx.Apple
orange=xxxx.Orange
只要修改配置文件即可。
Spring IOC 容器的的顶层接口时BeanFactory,但是我们一般使用的时ApplicationContext接口,三个常用的实现类AnnotationConfigApplicationContext、FileSystemXmlApplicationContext、ClassPathXmlApplicationContext
类型名 | 简介 |
---|---|
ClassPathXmlApplicationContext | 通过读取类路径下的 XML 格式的配置文件创建 IOC 容器对象 |
FileSystemXmlApplicationContext | 通过文件系统路径读取 XML 格式的配置文件创建 IOC 容器对象 |
ConfigurableApplicationContext | ApplicationContext 的子接口,包含一些扩展方法refresh() 和 close() ,让 ApplicationContext 具有启动、关闭和刷新上下文的能力 |
WebApplicationContext | 专门为 Web 应用准备,基于 Web 环境创建 IOC 容器对象,并将对象引入存入 ServletContext 域中 |
举例:基于XML管理bean
//创建一个类
public class HelloWorld {
public void sayHello() {
System.out.println("helloworld");
}
}
//resource目录下创建xml配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="helloworld" class="ioc.beanWithXml.HelloWorld">bean>
beans>
//创建测试类
public class testHelloworld {
@Test
public void testHelloWorld(){
ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloWorld helloworld = (HelloWorld) classPathXmlApplicationContext.getBean("helloworld");
helloworld.sayHello();
}
}
是怎么通过xml就可以获得 helloworld对象的呢?反射的运用。
1.aop是什么?
AOP是一种思想,对oop思想的一种补充,在不修改代码的前提下添加一种额外的功能
也叫面向切面编程,将一些与主要业务无关的,但有有一定通用性的功能代码,比如说 日志等,单独拎取出来。需要调用的时候调用就好了。
相关概念
横切关注点:对目标对象来说的,非核心业务
通知:非核心业务在切面中的调用
切面:封装横切关注点的类,或者说是封装通知方法的类
目标:被代理的目标对象
代理:向目标对象应用通知之后创建的代理对象。
连接点:标识要加入的额外功能的位置
AOP的总体流程:抽和插,目标对象是提前就有的,代理对象是JDK 动态代理帮助我们生成的,
从目标对象中,把非核心业务抽取出来,非核心业务就叫做横切关注点,横切关注点封装到类中,这个类就叫做切面,在切面中,每一个横切关注点都是一个方法,这个方法就叫做通知,通知有不同的类型,再定位到目标对象抽取横切关注点的位置,这个位置就叫做连接点,连接点是通过切入点定位的。
基于注解的AOP实现
aspectJ
编译时织入(应用到java代码的过程)
注意:AOP的底层只是用到了反射,最底层的原理主要是动态代理,动态代理中包含有反射。
比如JDK动态代理
1.被代理类实现一个接口
2.创建代理对象,需要实现InvocationHandler
3.代理过程在invoke中实现。
//被代理的类
public interface Calculator {
int add(int i, int j);
int sub(int i, int j);
int mul(int i, int j);
int div(int i, int j);
}
//被代理类的实现
public class CalculatorImpl implements Calculator {
public int add(int i, int j) {
int result = i + j;
System.out.println("方法内部 result = " + result);
return result;
}
public int sub(int i, int j) {
int result = i - j;
System.out.println("方法内部 result = " + result);
return result;
}
public int mul(int i, int j) {
int result = i * j;
System.out.println("方法内部 result = " + result);
return result;
}
public int div(int i, int j) {
int result = i / j;
System.out.println("方法内部 result = " + result);
return result;
}
}
现在有一个需求:在计算的前后增加日志
普通实现
public class CalculatorLogImpl implements Calculator {
public int add(int i, int j) {
System.out.println("[日志] add 方法开始了,参数是:" + i + "," + j);
int result = i + j;
System.out.println("方法内部 result = " + result);
System.out.println("[日志] add 方法结束了,结果是:" + result);
return result;
}
public int sub(int i, int j) {
System.out.println("[日志] sub 方法开始了,参数是:" + i + "," + j);
int result = i - j;
System.out.println("方法内部 result = " + result);
System.out.println("[日志] sub 方法结束了,结果是:" + result);
return result;
}
public int mul(int i, int j) {
System.out.println("[日志] mul 方法开始了,参数是:" + i + "," + j);
int result = i * j;
System.out.println("方法内部 result = " + result);
System.out.println("[日志] mul 方法结束了,结果是:" + result);
return result;
}
public int div(int i, int j) {
System.out.println("[日志] div 方法开始了,参数是:" + i + "," + j);
int result = i / j;
System.out.println("方法内部 result = " + result);
System.out.println("[日志] div 方法结束了,结果是:" + result);
return result;
}
}
动态代理
下面就有用到了反射
public class ProxyFactory {
//代理对象的工厂类
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
public Object getProxy(){
/***
* newProxyInstance():创建一个代理实例
* * 其中有三个参数:
* * 1、classLoader:加载动态生成的代理类的类加载器
* * 2、interfaces:目标对象实现的所有接口的class对象所组成的数组
* * 3、invocationHandler:设置代理对象实现目标对象方法的过程,即代理类中如何重写接 口中的抽象方法
* */
ClassLoader classLoader=target.getClass().getClassLoader();//获得类加载器
Class<?>[] interfaces = target.getClass().getInterfaces();//获取接口
InvocationHandler invocationHandler=new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/*** proxy:代理对象 * method:代理对象需要实现的方法,即其中需要重写的方法 * args:method所对应方法的参数
* */
System.out.println("日志:方法名:"+method.getName()+"参数:"+ Arrays.toString(args));
Object invoke = method.invoke(target, args);
System.out.println("结果:"+invoke);
return invoke;
}
};
return Proxy.newProxyInstance(classLoader,interfaces,invocationHandler);
}
}
调用
public class ProxyTest {
public static void main(String[] args) {
//普通调用方法
// Calculator cal=new CalculatorImpl();
// cal.add(1,2);
//调用有日志的方法
// Calculator calLog=new CalculatorLogImpl();
// calLog.add(1,2);
//
// System.out.println("#################");
// Calculator calStaticProxy=new CalculatorStaticProxy(calLog);
// calStaticProxy.add(1,2);
ProxyFactory proxyFactory=new ProxyFactory(new CalculatorImpl());
Calculator proxy = (Calculator) proxyFactory.getProxy();//如果不转型 不知道要调用哪个方法
proxy.add(1,2);
}
}
2.AOP的使用场景
Authentication 权限
Caching 缓存
Context passing 内容传递
Error handling 错误处理
Lazy loading 懒加载
Debugging 调试
logging, tracing, profiling and monitoring 记录跟踪 优化 校准
Performance optimization 性能优化
Persistence 持久化
Resource pooling 资源池
Synchronization 同步
Transactions 事务