spring原理知识点ioc、aop

一、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>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值