文章目录
一、ioc(Inversion of Control),控制反转 一种设计思想
1.在传统的程序中,对象创建与依赖都是编码在程序内部,对象的创建由程序自己控制。
控制反转后,将对象的创建转移给了第三方,就是springioc容器,由spring容器帮我们管理创建对象,依赖注入DI。
总结,获取依赖对象的方式反转了。
2.ioc实现:xml配置、注解。spring初始化,先读取配置文件,根据配置文件或原数据创建组织对象存入容器中。程序使用时再从ioc容器中取出所需对象。
spring默认单例模式 (singleton),同个对象实例化都一样,
原型模式(prototype) ,每次实例化都不一样
<bean id="address2" class="com.zjw.Address" scope="singleton">
<property name="strName" value="未知路"></property>
<property name="strNum" value="699"></property>
</bean>
注解@cofigruation @bean
@Configuration //配置类,相当于Compoent,注册到容器中,由srping容器管理
public class MyConfig {
//注册一个bean,相当于一个bean标签,方法的名字为bean的id,返回值相当于class属性
@Bean
public Student getUser(){
return new Student;
}
}
Spring 中的 IOC 的底层实现原理就是反射机制,Spring 的容器会帮我们创建实例,该容器中使用的方法就是反射,通过解析 xml 文件,获取到 id 属性和 class 属性里面的内容,利用反射原理创建配置文件里类的实例对象,存入到 Spring 的 bean 容器中。
二、AOP
1.动态代理
关于class类(反射)
JAVA反射机制
是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
西瓜名字 <——>西瓜画面
前提(jvm已经加载过该类,相当于人脑有这个记忆)
电脑反射机制就是一个抽象类名能够在记忆中(类加载内存)找到匹配的类的信息
用途:
在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法。
通过反射获取类的完整结构
类名 | 用途 |
---|---|
class类 | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Field类 | 代表类的成员变量(成员变量也称为类的属性) |
Method类 | 代表类的方法 |
Constructor类 | 代表类的构造方法 |
获取对象的class (四种方法)
Class clazz = String.class //已知具体的类,通过类的class属性获取
Class clazz = user.getClass();//已知某个类的实例,调用该实例的getclass()方法
Class clazz = Class.forName("全类名") //根据类的全类名(包名+类名),获取class对象
//方法四:通过类加载器;
ClassLoader cl = this.getClass().getClassLoader()
Class clazz=cl.loadClass("类的全类名")
下面例子使用的实体类
public class Student extends Person{
public String school;
private String privateSchool;
public Student() {
System.out.println("Student调用的是无参构造");
}
public Student(String school) {
System.out.println("Student调用的公有有参构造");
this.school = school;
}
private Student(String name,int age){
System.out.println("Student调用的是私有有参构造");
this.name = name;
this.age = age;
}
public void eat(){
System.out.println("吃东西");
}
public void move(String m){
System.out.println("在移动");
}
public void setInfo(String name,String school){
this.name=name;
this.school=school;
System.out.println("这是公有setInfo方法 带2参数"+name);
}
private void test(String name) {
System.out.println("这是私有test方法 带1参数");
}
public String getSchool(){
return this.school;
}
}
使用反射可以取得
1.实现的全部接口
public Class<?>[] getInterfaces() 获得当前类实现的类或是接口
2.所继承的父类
public Class<? Super T>[] getSuperclass() 获得当前类继承的父类的class
Class clazz = Class.forName("全类名");//通过全类名,调用Class.forName方法获取指定类的class实例
Class superClazz = clazz.getSuperclass(); //获取父类
System.out.println(superClazz.getName());
Class[] interfaces = clazz.getInterfaces(); //获取当前类的所有接口
for(Class c:interfaces){
System.out.println(c.getName);
}
3.获取类构造方法
公有getConstructors() ,私有getDeclaredConstructors(),
修饰符clazz.getModifiers(),参数类型clazz.getTypeParameters()
public class Test1 {
public static void main(String[] args) throws ClassNotFoundException {
Class clazz = Class.forName("Student");
System.out.println(clazz.getName());
Constructor[] constructors = clazz.getConstructors();
for (Constructor con:constructors){
System.out.println("构造方法名称:"+con.getName()+",修饰符:"+ clazz.getModifiers());//获取构造方法名称和修饰符
Class[] parameterTypes = con.getParameterTypes();
for (Class pt :parameterTypes) {
System.out.println("参数类型:"+pt.getName());
}
}
}
//**用反射的构造方法创建对象**
Object obj = clazz.newInstance();//相当于调用类的无参构造
Student stu = (Student)obj;
System.out.println(stu.getClass());
Constructor c = clazz.getConstructor(String.class);//指定获取一个参数String的构造方法
Student stu1 = (Student)c.newInstance("三小");//相当于调用类的有参构造
System.out.println(stu1.school);
Constructor dc = clazz.getDeclaredConstructor(String.class,int.class);//指定获取2个参数的构造方法
dc.setAccessible(true);//解除私有封装,强制调用私有构造方法
Student stu2 = (Student)dc.newInstance("张三", 12);
System.out.println(stu2.name+stu2.age);
}
4.获取类的方法
public Method[] getDeclaredMethods(): 返回此class对象所表示的类或接口的全部方法
getMethods(): 获取public方法
method类中:
public Class<?> getReturnType() 取得全部返回值类型
public Class<?> getParameterTypes() 取得全部参数
public int getModifiers取得全部返回值修饰符
Method[] methods = clazz.getMethods();
for (Method mth:methods
) {
System.out.println(mth.getName());//获取方法名
System.out.println(mth.getReturnType());//获取方法类型
System.out.println(mth.getModifiers());//获取修饰符
Class<?>[] parTypes = mth.getParameterTypes();//获取参数类型 是一个数组
for (Class p:parTypes){
System.out.println("参数类型"+p.getName());
}
}
4.获取类的属性
getFields() :获取类的公有属性
getDeclaredFields() : 获取类的全部属性
Field中:
getModifiers(): 已整数形式返回修饰符
public Class<?> getType() :获取Field的属性类型
getName() 返回Field名称
一,通过反射调用类中指定方法、属性
方法
getMethod() 获取公有方法 getDeclaredMethod获取私有构造方法
Class clazz = Class.forName("Student");
Object obj = clazz.newInstance();//相当于调用类的无参构造 创建对象
Student stu = (Student)obj;
Method method = clazz.getMethod("setInfo", String.class, String.class);//获取公有方法调用
method.invoke(stu,"张三","二小");//参数1是实例化的对象,后面的参数是调用方法的实际参数
Method declaredMethod = clazz.getDeclaredMethod("test", String.class);//获取私有方法
declaredMethod.setAccessible(true);//解除私有封装,强制调用私有构造方法
declaredMethod.invoke(obj,"zhangsan");
属性 getField(“属性名”); getDeclaredField(“属性名”);
Class clazz = Class.forName("Student");
Object obj = clazz.newInstance();//相当于调用类的无参构造
Student stu = (Student)obj;
Field f = clazz.getField("school");
f.set(stu,"公有属性一小");
String sch =(String) f.get(stu);
System.out.println(sch);
Field f2 = clazz.getDeclaredField("privateSchool");
f2.setAccessible(true);
f2.set(stu,"私有属性一小");
String sch2 =(String) f2.get(stu);
System.out.println(sch2);
2动态代理实现
//实现类
public class ITestDemoImpl implements ITestDemo {
@Override
public void test1() {
System.out.println("执行方法1");
}
@Override
public void test2() {
System.out.println("执行方法2");
}
}
/*
动态代理类
*/
public class ProxyDemo implements InvocationHandler {
Object obj;//定义一个参数 放被代理的对象
public ProxyDemo(Object obj){
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName()+"开始执行");
Object res = method.invoke(this.obj, args);//执行指定代理对象的指定方法
System.out.println(method.getName()+"执行完毕");
return res;
}
}
public class Test2 {
public static void main(String[] args) {
/*
通过Proxy.newProxyInstance方法被代理的对象,必须要接口+实现类
*/
ITestDemo test = new ITestDemoImpl();
test.test1();
test.test2();
InvocationHandler handler = new ProxyDemo(test);
/*
Proxy.newProxyInstance(ClassLoader,interfaces,h)
参数1:代理对象的类加载器
参数2:被代理对象的接口
参数3:代理对象
返回值:被成功代理后的对象 即test对象
*/
ITestDemo t = (ITestDemo) Proxy.newProxyInstance(handler.getClass().getClassLoader(), test.getClass().getInterfaces(), handler);
t.test1();
}
}
3.spring aop实现
pom导包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
方法一:使用原生spring api接口
实现类UserServiceImpl
@Service
public class UserServiceImpl implements UserService{
public void add() {
System.out.println("add方法");
}
public void delete() {
System.out.println("delete方法");
}
}
bean.xml配置
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 包扫码 用注释方式-->
<context:component-scan base-package="com.zjwaop"></context:component-scan>
<!-- 配置aop:导入约束-->
<aop:config>
<!-- pointcut切入点 ; expression表达式 固定格式-->
<aop:pointcut id="po1" expression="execution(* com.zjwaop.service.UserServiceImpl.*(..))"/>
<!-- advisor通知:切面要完成的工作,即类的方法 ==》执行环绕增强-->
<aop:advisor advice-ref="beforeLog" pointcut-ref="po1"></aop:advisor>
<aop:advisor advice-ref="afterLog" pointcut-ref="po1"></aop:advisor>
</aop:config>
</beans>
测试
public class MyTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
UserService us = (UserService)ac.getBean("userServiceImpl");
us.add();
}
}
方法二:自定义类
@Component
public class DiyAop {
public void be(){
System.out.println("be前===");
}
public void af(){
System.out.println("af后===");
}
}
<aop:config>
<!-- 自定义切面,ref要引用的类-->
<aop:aspect ref="diyAop">
<!-- 切入点-->
<aop:pointcut id="po2" expression="execution(* com.zjwaop.service.UserServiceImpl.*(..))"/>
<!-- 通知-->
<aop:before method="be" pointcut-ref="po2"></aop:before>
<aop:after method="af" pointcut-ref="po2"></aop:after>
</aop:aspect>
</aop:config>
方式三:注释实现
@Component
@Aspect//这是一个切面类
public class AnnotationAop {
@Before("execution(* com.zjwaop.service.UserServiceImpl.*(..))")
public void annBe(){
System.out.println("annoBe前===");
}
@After("execution(* com.zjwaop.service.UserServiceImpl.*(..))")
public void annAf(){
System.out.println("annoAf后===");
}
}
<!-- 开启aop注解支持-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>