反射
1.什么是反射
1)Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。
2)Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。
2.常用的类文件
3.反射的作用
类的加载器可以获得类中的东西:属性,构造方法,功能方法。即
- 动态创建对象
- 动态操作属性
- 动态调用方法
4.反射的入口——class类
IOC/DI
IOC(控制反转):以前依赖的对象自己直接new,现在不需要new,框架会自动注入,创建对象的权利转移给了框架
DI(依赖注入):一个类的功能需要依赖另一个类的配合,同时需要赋上一个具体的对象,则这种关系是依赖注入
Spring框架负责所有对象的创建、管理和依赖注入,所有对象储存的容器叫做IOC容器
代码展示
核心配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<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">
</beans>
dao层:
package com.gao.dao;
public interface BookDao {
public void study();
}
package com.gao.dao.impl;
import com.gao.dao.BookDao;
public class BookDaoImpl implements BookDao {
@Override
public void study() {
}
}
service层
package com.gao.service.impl;
import com.gao.dao.BookDao;
import com.gao.service.BookService;
public class BookServiceImpl implements BookService {
private BookDao bookDao;
@Override
public void save() {
System.out.println("BookServiceImpl---------save");
bookDao.study();
}
}
package com.gao.service;
public interface BookService {
void save();
}
servlet层:
package com.gao.servlet;
import com.gao.service.BookService;
import com.gao.service.impl.BookServiceImpl;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BookServlet {
BookService bookService;
@Test
public void add(){
System.out.println("bookService---------");
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("Spring.xml");
bookService= (BookService) context.getBean("bookService");
bookService.save();
}
}
动态代理
动态代理
动态代理是一种常用的设计模式,广泛应用于框架中,Spring框架的AOP特性就是应用动态代理实现的,想要理解AOP的实现原理我们就必须先理解动态代理。
什么是代理模式
代理模式是GOF23设计模式之一,代理模式中存在代理者和被代理者,代理者和被代理者都具有相同的功能,并且代理者执行功能时会附加一些额外的操作
如:手机工厂和代理商都具有卖东西的功能,手机代理商除了帮工厂卖手机外,还能在卖手机前打广告推销,卖手机后还可以进行售后服务
代理模式的优点
- 符合开闭原则,不用修改被代理者任何的代码,就能扩展新的功能
- 项目的扩展和维护比较方便
示例代码
public static void main(String[] args) {
//明确要代理的对象
Actor cxk=new CXK();
/**
* 创建代理对象,具体某个人作为经纪人,对代理对象的方法进行服务(功能增强)
* 参数1,ClassLoader loader 被代理的类的类加载器(底层使用的反射)
* 2,Class<?>[] interfaces 被代理的类的接口类型(类型的判断)
* 3,InvocationHandler h 被代理后要做什么事情
*/
Actor jjr= (Actor) Proxy.newProxyInstance(CXK.class.getClassLoader(), CXK.class.getInterfaces(), new InvocationHandler() {
/**
* Object proxy:被代理对象的一个引用
* Method method:被代理对象的方法
* Object[] args:方法被执行时需要的参数列表
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//前置增强
System.out.println("进行巡演造势");
//方法的三要素
Object result=null;
String methodName= method.getName();
System.out.println(methodName);
//方法执行需要一个对象的引用
result=method.invoke(cxk,args);
//后置增强
System.out.println("结算和纳税");
return result;
}
});
//3,执行方法,由代理对象进行执行
jjr.sing(5,3.14);
jjr.rap();
}
}
AOP
什么是AOP?
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
简单来说:使用AOP可以在不修改源码的基础上,增加新的功能。(显而易见,这对于大型项目开发来说是极具诱惑的。减少了版本更迭时的工作量)
AOP是什么原理?
AOP代表的是一个横向的关系,相比于纵向的继承关系更加简便。将“对象”比作一个空心的圆柱体,其中封装的是对象的属性和行为;则面向方面编程的方法,就是将这个圆柱体以切面形式剖开,可以选择性的提供业务逻辑。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹,但完成了效果。
Spring AOP 底层实现
- JDK 动态代理:基于接口实现
- CGLib 是基于类的继承实现的
五种通知形式
Before advice :前置通知,目标方法前执行,无论目标方法是否遇到异常都执行
After returning advice:后置通知,目标方法执行后执行,前提是目标方法没有遇到异常,遇到异常则不执行
After throwing advice:异常通知,顾名思义,在目标方法抛出异常时执行
After finally advice:最终通知,在目标方法执行后执行,无视是否异常
Around advice:环绕通知:最强大的通知类型,可以控制目标方法的执行(通过调用ProceedingJoinPoint.proceed() 执行目标方法),可以在目标执行全过程中执行。
实现
2. 创建UserService类,这个类完成核心功能操作。
void findAll();
void save(int a);
int del();
void update();
/**
* 核心类
*/
public class BookServiceImpl implements BookService {
@Override
public void findAll() {
System.out.println("查询所有");
}
@Override
public void save(int a) {
System.out.println("保存信息"+a);
}
@Override
public int del() {
System.out.println("删除信息");
return 5;
}
@Override
public void update() {
System.out.println("修改信息");
}
}
创建Logger类,这个类是用来做功能的增强。
/**
* 增强类
*/
public void check() {
System.out.println("前置通知/增强:权限验证");
}
public void logprint(){
System.out.println("后置通知/增强:日志输出");
}
public void exception(){
System.out.println("异常通知/增强:异常处理");
}
public void distory(){
System.out.println("最终通知/增强:资源释放");
}
}
在spring的beans.xml中开始进行AOP的配置:
首先把核心类和增强类的bean配置到IOC的容器中
使用<aop:config>标签在进行AOP的配置,先通过aop:aspect标签标明谁是增强类。然后在标签中进行aop:before(前置)、aop:after-returning(后置)、aop:after-throwing(异常)、aop:after(最终)的配置,让增强类的某个方法对核心功能类的某一类方法进行功能增强。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--1.把所有类的对象交给IOC容器进行管理-->
<bean id="logger" class="com.gao.logger.Logger"/>
<bean id="bookService" class="com.gao.service.impl.BookServiceImpl"/>
<!--2.AOP的配置:让增强类 的 哪个方法 动态进行何种增强 核心类 的 哪个方法-->
<aop:config>
<!--指定增强类并起个名字-->
<aop:aspect id="check" ref="logger">
<!--前置通知/增强:在核心类方法执行之前 进行 增强-->
<aop:before method="check" pointcut="execution(* *..BookServiceImpl.*(..))"/>
<aop:before method="logprint" pointcut="execution(* *..BookServiceImpl.*(..))"/>
<aop:before method="exception" pointcut="execution(* *..BookServiceImpl.*(..))"/>
<aop:before method="distory" pointcut="execution(* *..BookServiceImpl.*(..))"/>
</aop:aspect>
</aop:config>
</beans>