Spring中IOC与AOP

基于注解配置Spring

基于XML配置Spring

引入log4j日志系统

依赖反转,

装配bean的方法:

  1. 隐式的bean发现机制和自动装配

1. Spring框架两大核心机制

  1. IOC(控制反转)/DI(依赖注入)
  2. AOP(面向切面编程)

1.1. IOC(控制反转)

在Spring框架中,创建对象的流程交给IOC容器来创建,使用解耦合的方式

从IOC的bean工厂中获取对象

  1. 通过ID获取

  2. 也可以通过运行时类获取(配置文件中只能存在该类的一个对象)


public void static main(String[] args){

        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        MessagePrinter printer = context.getBean(MessagePrinter.class);//运行时类
        //MessagePrinter printer = context.getBean("printer");//ID

        printer.printMeaasge();

        System.out.println(printer.toString());
}

1.1.1. 配置XML文件实现IOC的创建对象

配置文件详解

  1. 通过配置bean标签来完成对bean类的管理
    1. id :表示对象名
    2. class:表示对象的对应类的全限定名(必须有无参构造函数)
  2. 对象的成员通过bean标签的子节点property来赋值(通过set()方法来赋值)
    1. name:成员变量名
    2. value:成员变量值(基本数据类型,String都可以直接赋值,其他引用类型不能通过value赋值)
    3. ref:将IOC中的另外一个bean赋给当前的成员变量(即DI)
     <?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">
    
         <!--
         bean元素:描述当前的对象需要由spring容器管理
         id属性:表示对象,可以根据id获取对象
         class:被管理对象的名字包名+类名
    
         service对象和成员变量的service对应
         ref和service对应
         -->
         <bean id="service" class="hello.MessageService">
             <property name="age" value="25"></property>
             <property name="id" value="1"></property>
             <property name="name" value="张三"></property>
         </bean>
         <bean id="printer"  class="hello.MessagePrinter">
             <property name="service" ref="service"></property>
             <property name="name" value="惠普"></property>
         </bean>
    
     </beans>
  3. 通过constrctor-args标签调用有参构造来赋值
    1. 可以加name以及value,设值
    2. 也可以按照构造参数的顺序来写,也可以通过index根据变量有参构造的顺序设定传入参数的顺序
    <?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">
        <bean id="service" class="hello.MessageService">
            <constructor-arg name="age" value="25"></constructor-arg>
            <constructor-arg name="id" value="1"></constructor-arg>
            <constructor-arg name="name" value="张三"></constructor-arg>
        </bean>
        <bean id="printer"  class="hello.MessagePrinter">
            <constructor-arg ref="service"></constructor-arg>
            <constructor-arg value="惠普"></constructor-arg>
        </bean>
        <!-- <bean id="printer"  class="hello.MessagePrinter">
            <constructor-arg index="0" ref="service"></constructor-arg>
            <constructor-arg index="1" value="惠普"></constructor-arg>
        </bean> -->
    
    </beans>
  4. 给bean类中注入集合

     <bean id="student" class="hello.MessagePrinter">
         <property name="age" value="33"></property>
         <property name="array">
             <list>
                 <ref bean="address"></ref>
                 <ref bean="address2"></ref>
             </list>
         </property>
     </bean>
     </bean>
    
     <bean id="address2" class="hello.MessageService">
     </bean>

1.1.2. IOC底层原理

  1. 读取配置文件解析XML
  2. 通过反射机制来实例化配置文件中配置的bean对象
package IOC;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class ClassPathXmlApplicationContext implements ApplicationContext {

    private Map<String,Object> ioc = new HashMap<>();

    public ClassPathXmlApplicationContext(String path){

        try {
            SAXReader reader = new SAXReader();
            Document documented = reader.read("./src/main/resources/"+path);
            Element root = documented.getRootElement();
            Iterator<Element> iterator = root.elementIterator();
            while (iterator.hasNext()){
                Element element = iterator.next();
                String id = element.attributeValue("id");
                String classname = element.attributeValue("class");

                Object object = Class.forName(classname).newInstance();//通过反射机制创建<bean>标签的对象
                ioc.put(id,object);//id值为设定的类名,value为对象

                Iterator<Element> beaniter = element.elementIterator();//通过<property>调用set方法给对象的属性赋值
                while (beaniter.hasNext()){
                    Element property = beaniter.next();
                    String name = property.attributeValue("name");
                    String value = property.attributeValue("value");
//                    System.out.println(value);
                    String ref = property.attributeValue("ref");
                    if(ref==null){
                        String methodName = "set"+name.substring(0,1).toUpperCase()+name.substring(1);
//                        System.out.println(methodName);
                        Field field = Class.forName(classname).getDeclaredField(name);
//                        System.out.println(field.getType());
                        Method method = Class.forName(classname).getMethod(methodName,field.getType());
//                        System.out.println(method);

                        //根据成员变量的数据类型将value进行转换,因为value为string类型的,
                        method.invoke(object,value);

                    }else{//在配置文件中DI的值必须定义在标签之上,如果在标签下会存在在map中找不到对象的情况

                        String methodName = "set"+name.substring(0,1).toUpperCase()+name.substring(1);

                        Object di = ioc.get(ref);

                        Field field = Class.forName(classname).getDeclaredField(name);

                        Method method = Class.forName(classname).getMethod(methodName,field.getType());//获取对象


                        //根据成员变量的数据类型将value进行转换,因为value为string类型的,
                        method.invoke(object,di);

                    }
                }
            }
        } catch (DocumentException | ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

    }

    @Override
    public Object getBean(String id) {
        return ioc.get(id);
    }
}

1.1.3. 标签的Scope属性

Spring 管理的 bean 是根据 scope 来生成的,表示 bean 的作用域,共4种,默认值是 单例模式。

  • singleton:单例,表示通过 IoC 容器的getBean方法获取的 bean 是唯一的。
  • prototype:原型,表示通过 IoC 容器的getBean方法获取的 bean 是不同的。
  • request:请求,表示在一次 HTTP 请求内有效。
  • session:回话,表示在一个用户会话内有效。

request 和 session 只适用于 Web 项目,大多数情况下,使用单例和原型较多。

prototype 模式当业务代码获取 IoC 容器中的 bean 时,即调用getBean()方法时,Spring 才去调用无参构造创建对应的 bean。

singleton 模式无论业务代码是否获取 IoC 容器中的 bean,Spring 在加载 spring.xml 时就会创建 bean.

1.1.4. 标签中bean类的继承

对于一个子对象来说,可以继承父对象的属性值,可以是不同类之间的继承。Spring 的继承关注点在于具体的对象,而不在于类,即不同的两个类的实例化对象可以完成继承,前提是子对象必须包含父对象的所有属性,同时可以在此基础上添加其他的属性

<bean id="student" class="com.Student">
    <property name="id" value="1"></property>
    <property name="name" value="张三"></property>
    <property name="age" value="22"></property>
    </property>
</bean>

<bean id="stu" class="com.Stu" parent="student">
    <property name="course" value="数学"></property>
</bean>
public class Student{
    private Integer id;
    private String name;
    private Integer age;
    //set方法等
}
public class Stu{
    private Integer id;
    private String name;
    private Integer age;
    private String course;
}

1.1.5. bean类的依赖

与继承类似,依赖也是描述 bean 和 bean 之间的一种关系,配置依赖之后,被依赖的 bean 一定先创建,再创建依赖的 bean,A 依赖于 B,先创建 B,再创建 A。

<?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-3.2.xsd
                           ">

    <bean id="student" class="com.southwind.entity.Student" depends-on="user"></bean>

    <bean id="user" class="com.southwind.entity.User"></bean>

</beans>

1.1.6. Spring的p命名空间

p 命名空间是对 IoC / DI 的简化操作,使用 p 命名空间可以更加方便的完成 bean 的配置以及 bean 之间的依赖注入,使用p简化书写,加xxx-ref代表为其他对象

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
">

    <bean id="student" class="com.southwind.entity.Student" p:id="1" p:name="张三" p:age="22" p:address-ref="address"></bean>


    <bean id="address" class="com.southwind.entity.Address" p:id="2" p:name="科技路"></bean>

</beans>

1.1.7. Spring的工厂方法获取bean对象

IoC 通过工厂模式创建 bean 的方式有两种:

  • 静态工厂方法
  • 实例工厂方法
<?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">


    <bean id="service" class="factory.springFactory" factory-method="get">
        <constructor-arg value="1"></constructor-arg>
    </bean>
</beans>
package factory;

import hello.MessageService;

import java.util.HashMap;
import java.util.Map;

public class springFactory {

    private static Map<Integer,MessageService> all = new HashMap<>();

    static {
        all.put(1,new MessageService("1","tom","55"));
        all.put(2,new MessageService("1","tom","55"));
    }

    public static MessageService get(Integer i){
        return all.get(i);
    }

}
package factory;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.sql.SQLOutput;

public class test {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-Factory.xml");
        System.out.println(context.getBean("service"));
    }
}

实例工厂方法

<?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">

    <!--静态工厂-->
    <bean id="service" class="factory.springFactory" factory-method="get">
        <constructor-arg value="1"></constructor-arg>
    </bean>

    <!--实例工厂-类->
    <bean id="carFactory" class="factory.InstanceFactory"></bean>

    <!--获取变量-->
    <bean id="s2" factory-bean="carFactory" factory-method="get">
        <constructor-arg value="1"></constructor-arg>
    </bean>
</beans>
package factory;

import hello.MessageService;

import java.util.HashMap;
import java.util.Map;

public class InstanceFactory {
    private Map<Integer, MessageService> alll;

    public InstanceFactory(){
        alll = new HashMap<>();
        alll.put(1,new MessageService("1","tom","55"));
        alll.put(2,new MessageService("1","tom","55"));
    }
    public MessageService get(Integer i){
        return alll.get(i);
    }

}

package factory;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.sql.SQLOutput;

public class test {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-Factory.xml");
        System.out.println(context.getBean("s2"));
    }
}

1.1.8. IoC 自动装载(Autowire)

IoC 负责创建对象,DI 负责完成对象的依赖注入,通过配置 property 标签的 ref 属性来完成,同时 Spring 提供了另外一种更加简便的依赖注入方式:自动装载,不需要手动配置 property,IoC 容器会自动选择 bean 完成注入。

自动装载有两种方式:

  1. byName:通过成员变量的属性名自动装载,即创建对象的名字与成员变量名相同
  2. byType:通过属性的数据类型自动装载,但是只能有一个这个类的实例
<bean id="service" class="hello.MessageService">
        <property name="name" value="tosssss"></property>
    </bean>
    <bean id="printer" class="hello.MessagePrinter" autowire="byName"><!--自动装载-->
        <property name="name" value="惠普"></property>
<!--        <property name="service" ref="service"></property>-->
    </bean>
<bean id="service" class="hello.MessageService">
        <property name="name" value="tosssss"></property>
    </bean>
    <bean id="printer" class="hello.MessagePrinter" autowire="byType"><!--自动装载-->
        <property name="name" value="惠普"></property>
<!--        <property name="service" ref="service"></property>-->
    </bean>

byType 需要注意,如果同时存在两个及以上的符合条件的 bean 时,自动装载会抛出异常。

1.2. AOP(面向切面编程)

Spring框架对动态代理进行封装。

Spring 框架中不需要创建 InvocationHandler,只需要创建一个切面对象,将所有的非业务代码在切面对象中完成即可,Spring 框架底层会自动根据切面类以及目标类生成一个代理对象。

使用动态代理实现

在Spring中实现

//代理类
package com.southwind.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Aspect//表示该类为切面类
@Component//给IOC来管理对象
public class LoggerAspect {

    @Before(value = "execution(public int com.southwind.utils.impl.CalImpl.*(..))")//表示位置,参数为类
    public void before(JoinPoint joinPoint){
        //获取方法名
        String name = joinPoint.getSignature().getName();
        //获取参数
        String args = Arrays.toString(joinPoint.getArgs());
        System.out.println(name+"方法的参数是:"+ args);
    }

    @After(value = "execution(public int com.southwind.utils.impl.CalImpl.*(..))")
    public void after(JoinPoint joinPoint){
        //获取方法名
        String name = joinPoint.getSignature().getName();
        System.out.println(name+"方法执行完毕");
    }

    @AfterReturning(value = "execution(public int com.southwind.utils.impl.CalImpl.*(..))",returning = "result")//returning以及参数Object必须相同
    public void afterReturning(JoinPoint joinPoint,Object result){
        //获取方法名
        String name = joinPoint.getSignature().getName();
        System.out.println(name+"方法的结果是"+result);
    }

    @AfterThrowing(value = "execution(public int com.southwind.utils.impl.CalImpl.*(..))",throwing = "exception")
    public void afterThrowing(JoinPoint joinPoint,Exception exception){
        //获取方法名
        String name = joinPoint.getSignature().getName();
        System.out.println(name+"方法抛出异常:"+exception);
    }
}

LoggerAspect 类定义处添加的两个注解:

  • @Aspect:表示该类是切面类。
  • @Component:将该类的对象注入到 IoC 容器。

具体方法处添加的注解:

@Before

委托对象的类 也需要添加 Component,交给 IoC 容器来管理。

package com.southwind.utils.impl;

import com.southwind.utils.Cal;
import org.springframework.stereotype.Component;

@Component
public class CalImpl implements Cal {
    public int add(int num1, int num2) {
        int result = num1+num2;
        return result;
    }

    public int sub(int num1, int num2) {
        int result = num1-num2;
        return result;
    }

    public int mul(int num1, int num2) {
        int result = num1*num2;
        return result;
    }

    public int div(int num1, int num2) {
        int result = num1/num2;
        return result;
    }
}

spring.xml 中配置 AOP。

<?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"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
">

    <!-- 自动扫描 -->
    <context:component-scan base-package="com.hello"></context:component-scan>

    <!-- 是Aspect注解生效,为目标类自动生成代理对象 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>
package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import utills.Cal;

import java.lang.reflect.Proxy;

public class Test {

    ApplicationContext context = new ClassPathXmlApplicationContext("AOP.xml");

    Cal proxy = (Cal)context.getBean("calImpl");//默认ID为委托类的名字首字母小写,可以通过委托类compoent(value="")配置

    proxy.add(1,1);

}

context:component-scanhello包中的所有类进行扫描,如果该类同时添加了 `@Component,则将该类扫描到 IoC 容器中,即 IoC 管理它的对象。

aop:aspectj-autoproxy 让 Spring 框架结合切面类和目标类自动生成动态代理对象。

  • 切面:横切关注点被模块化的抽象对象。
  • 通知:切面对象完成的工作。
  • 目标:被通知的对象,即被横切的对象。
  • 代理:切面、通知、目标混合之后的对象。
  • 连接点:通知要插入业务代码的具体位置。
  • 切点:AOP 通过切点定位到连接点。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值