spring_DI/IOC与AOP

一 Spring的复习与导包

1.1 什么是Spring

  • 轻量级的DI/IOC与AOP的容器框架!
  • 面试题:BeanFactory与ApplicationContext的区别?

1.2 导包

Spring需要的包

 <!--Spring的核心包-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>4.2.5.RELEASE</version>
</dependency>
<!--Context包-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.2.5.RELEASE</version>
</dependency>
<!--aop的包-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>4.2.5.RELEASE</version>
</dependency>
<!--切面的一个包(织入)-->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.8</version>
</dependency>

<!-- Spring的测试包 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>4.2.5.RELEASE</version>
    <!--scope:范围,只能在test包中使用-->
    <scope>test</scope>
</dependency>
<!--junit的测试支持-->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

引入一些插件与资源

  • 需要去读到java中的xml文件(默认不会编译)
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
        </resource>
        <resource>
            <directory>src/test/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
        </resource>
    </resources>
</build>

二 构造器注入

  • 标签: constructor-arg
  • 属性 index/name/type = 下标/名称/类型
  • 属性 value/ref = 普通的值/引用

2.1 根据下标进行引入

<bean id="myBean" class="cn.itsource._02_constructor.MyBean">
    <constructor-arg index="0" value="小莫" />
    <constructor-arg index="1" value="99" />
</bean>

2.2 根据名称进行引入

<bean id="myBean" class="cn.itsource._02_constructor.MyBean">
    <constructor-arg name="name" value="小莫" />
    <constructor-arg name="age" value="99" />
</bean>

2.3 根据类型进行引入

不能出现重复类型

<bean id="myBean" class="cn.itsource._02_constructor.MyBean">
    <constructor-arg type="java.lang.String" value="小莫" />
    <constructor-arg type="java.lang.Integer" value="99" />
</bean>

2.4 自动进行引入

顺序是不允许修改的

<bean id="myBean" class="cn.itsource._02_constructor.MyBean">
    <constructor-arg value="小莫" />
    <constructor-arg value="99" />
</bean>

2.5 在其它的bean的方式

外部bean是可以重复使用

<bean id="otherBean" class="cn.itsource._02_constructor.OtherBean">
    </bean>
    
<bean id="myBean" class="cn.itsource._02_constructor.MyBean">
    <!-- 外部bean -->
    <constructor-arg index=0 ref="otherBean" />
    <!-- 内部bean -->
    <constructor-arg index="2">
        <bean class="cn.itsource._02_constructor.OtherBean" />
    </constructor-arg>
</bean>

三 属性注入

3.1 普通属性

准备属性

// 简单属性
private Long id;
private String name;
private Boolean sex;
private BigDecimal salary;

配置的代码

<property name="id" value="1" />
<property name="name" value="小马" />
<property name="sex" value="true"/>
<property name="salary" value="1024" />

3.2 集合

准备的属性

  • list与set(不允许重复)
  • 关键的那个标签(list,set,array)写错也可以用(但是不建议)
private List<String> list;
private Set<String> set;
private List<OtherBean> otherBeanList;
private Set<OtherBean> otherBeanSet;

配置的代码

<property name="list">
   <list>
       <value>abc</value>
       <value>abc</value>
       <value>123</value>
       <value>321</value>
   </list>
</property>
<!--Set<String> set :无序,不重复-->
<property name="set">
   <set>
       <value>abc</value>
       <value>abc</value>
       <value>123</value>
       <value>321</value>
   </set>
</property>
<!--List<OtherBean> otherBeanList-->
<property name="otherBeanList">
   <list>
        <ref bean="otherBean" />
        <ref bean="otherBean" />
        <bean class="cn.itsource._03_di.OtherBean" />
        <bean class="cn.itsource._03_di.OtherBean" />
   </list>
</property>
<!--Set<OtherBean> otherBeanSet-->
<property name="otherBeanSet">
   <set>
       <ref bean="otherBean" />
       <ref bean="otherBean" />
       <bean class="cn.itsource._03_di.OtherBean" />
       <bean class="cn.itsource._03_di.OtherBean" />
   </set>
</property>

3.3 数组与properties

  • 数组与properties都有两种写法(简写形式)
  • properties的简写形式不支持中文

数组与properties

private String[] arrays;
private Properties props1;
private Properties props2;

xml配置

<!--String[] arrays :标准写法 -->
<!--
<property name="arrays">
   <array>
       <value>abc</value>
       <value>def</value>
       <value>gf</value>
   </array>
</property>
-->
<!--String[] arrays :简写形式 (数组中每个值用,隔开)-->
<property name="arrays" value="abc,dfe,fd" />
<!--Properties props1:标准写法-->
<property name="props1">
   <props>
       <prop key="driver">com.mysql.jdbc.Driver</prop>
       <prop key="url">jdbc:mysql:///spring哈哈</prop>
       <prop key="username">root</prop>
       <prop key="password">admin</prop>
   </props>
</property>
<!--Properties props2:简写形式(不支持中文)-->
<property name="props2">
   <value>
       driver=com.mysql.jdbc.Driver
       url=jdbc:mysql:///spring哈哈
       username=root
   </value>
</property>

四 XML的自动注入(了解即可)

  • 自动注入有两种方式 (类型与名称)
  • 设置全局的自动注入 <beans … default-autowire=“byType/byName”>
  • 单独为某一个bean配置自动注入 <bean … autowire=“byType/byName”>

五 全注解(重要)

5.1 扫描相应的包

注意:引入context的头 <context:component-scan base-package=“cn.itsource._05_anno” />

5.2 在相应的类上加注解

  • Controller:控制层

  • Service:业务层

  • Repository:持久层

  • Component:组件(一个bean不知道在哪一层用这个)

  • @Autowired:注入功能

5.3 如果出现多个bean类型一样怎么办?

  • 注解的bean有默认名称(类名【首字母小写】) 如 userDaoImpl
  • 修改bean的名称 Component/Service/Repository/Controller(“名称”)
  • 在注入bean的时候加上一个限定注解
@Autowired
@Qualifier("userJPADaoImpl")
//@Resource(name = "userJDBCDao")
private IUserDao userDao;

六 代理模式(了解即可)

  • 分为静态与动态
  • Spring使用的是动态代码:JDK(接口)/CGLIB
  • 动态代理的代码
//通过JDK的方案创建一个动态代理对象呢?
/**
 * java.lang.reflect:Proxy(代理)对象
 * Foo Bar:张三,李四,王五
 *   ClassLoader loader :类加载器(随便给它一个)
     Class<?>[] interfaces:接口(为什么这里是一个数组)
     InvocationHandler h :增强功能(自己实现)
 */
IEmployeeService proxy = (IEmployeeService)Proxy.newProxyInstance(
    this.getClass().getClassLoader(),
    employeeService.getClass().getInterfaces(),
    new InvocationHandler() {
        /**
         * @param proxy :代理对象(没有用)
         * @param method :执行的方法
         * @param args :方法中的参数
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object result = null;
            try {
                txManager.begin();
                //在这里面完成功能增强
                //通过反射执行相应的方法
                result = method.invoke(employeeService, args);
                txManager.commit();
            } catch (Exception e) {
                txManager.rollback();
                e.printStackTrace();
            } finally {
                txManager.close();
            }
            return result;
        }
    });

七 Spring的AOP

7.1 XML版本

准备接口:IEmployeeService

public interface IEmployeeService {
    void save();
    void update();
    void delete();
}

准备实现 EmployeeServiceImpl

public class EmployeeServiceImpl implements IEmployeeService {
    @Override
    public void save() {
        System.out.println("送花给你....");
    }

    @Override
    public void update() {
        System.out.println("EmployeeServiceImpl udpate..");
    }

    @Override
    public void delete() {
        System.out.println("EmployeeServiceImpl delete..");
        //int i = 1/0;
    }
}

事务管理器(假)

public class TxManager {

    public void begin(){
        System.out.println("开启事务...");
    }

    public void commit(){
        System.out.println("提交事务...");
    }

    public void rollback(Throwable e){
        System.out.println("回滚事务...,错误的原因:"+e.getMessage());
    }

    public void close(){
        System.out.println("关闭资源...");
    }

    //搞了一个ProceedingJoinPoint(连接点对象)
    public void around(ProceedingJoinPoint joinPoint){
        System.out.println(joinPoint.getArgs()); //参数
        System.out.println(joinPoint.getSignature()); //方法签名(这个方法的所有信息)
        System.out.println(joinPoint.getTarget().getClass()); //真实主题角色
        System.out.println(joinPoint.getThis().getClass()); //代理主题角色
        try {
            begin();
            joinPoint.proceed(); //执行对应的方法
            commit();
        } catch (Throwable e) {
            rollback(e);
            e.printStackTrace();
        } finally {
            close();
        }
    }

}

配置(关键)

  • 引入aop的头
  • 准备两个bean(EmployeeServiceImpl,TxManager)
  • 如果有环绕通知,其它通知就不需要了
  • 注意:何时,何地,做什么
<?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"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
">

    <!--真实主题角色-->
    <bean id="employeeService" class="cn.itsource._08_xmlaop.EmployeeServiceImpl" />

    <!--准备一个事务-->
    <bean id="txManager" class="cn.itsource._08_xmlaop.TxManager" />

    <!--何时,何地,做什么事-->
    <!--代表要做一个AOP的配置-->
    <aop:config>
        <!--
            配置(定义)切点 在哪些类的哪些方法进行功能
                id:切点名称(随便取)
                expression:表达式(最后定位都是方法)
                    *:所有返回值
                    cn.itsource._08_xmlaop:对应的包
                    I*Service:以I开头,Service结尾的所有接口(所有实现接口的方法)
                    *:所有方法
                    (..):所有参数
          -->
        <aop:pointcut id="pointcut" expression="execution(* cn.itsource._08_xmlaop.I*Service.*(..))" />
        <!--
            切面:由切点和增强组成
                ref="txManager" -> 对应的增强类
        -->
        <aop:aspect ref="txManager">
            <!--
            aop:before:前置通知
                何地:在哪些类的哪些方法中:pointcut
                何时:在方法执行之前:before
                做什么事:执行txManager这个bean中的begin方法
                 try {
                        //前置通知
                        result = method.invoke(employeeService, args);
                        //后置通知
                    } catch (Exception e) {
                        //异常通知
                    } finally {
                        //最终通知
                    }
            -->
            <!--<aop:before method="begin" pointcut-ref="pointcut" />-->
            <!--后置通知-->
            <!--<aop:after-returning method="commit" pointcut-ref="pointcut"  />-->
            <!--异常通知 throwing这个错,方法中才可以获到(名字必需一致) -->
            <!--<aop:after-throwing method="rollback" pointcut-ref="pointcut" throwing="e" />-->
            <!--最终通知 -->
            <!--<aop:after method="close" pointcut-ref="pointcut"  />-->
            <!--环绕通知-->
            <aop:around method="around" pointcut-ref="pointcut"  />
        </aop:aspect>
    </aop:config>
</beans>

测试

  • 查看一下这个对象是否已经被代理
  • 声明必需是接口
  • 测试一下有异常与没有异常的区别

7.2 注解版

  • 需要在相应的bean上加注解
  • 配置包的扫描
  • 所有的配置都是在TxManager加注解

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: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
">
    <!--扫描包-->
    <context:component-scan base-package="cn.itsource._09_annoaop" />
    <!--支持切面的注解-->
    <aop:aspectj-autoproxy />
</beans>

TxManager

  • 切点的名字是方法名()
package cn.itsource._09_annoaop;

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

/**
 * @Aspect -> <aop:aspect ref="txManager">
 */
@Component
@Aspect
public class TxManager {
    /**
     * 切点:
     * <aop:pointcut id="pointcut()" expression="execution(* cn.itsource._09_annoaop.I*Service.*(..))" />
     */
    @Pointcut("execution(* cn.itsource._09_annoaop.I*Service.*(..))")
    public void pointcut(){}

//    @Before("pointcut()")
    public void begin(){
        System.out.println("开启事务...");
    }

//    @AfterReturning("pointcut()")
    public void commit(){
        System.out.println("提交事务...");
    }

//    @AfterThrowing(pointcut = "pointcut()",throwing = "e")
    public void rollback(Throwable e){
        System.out.println("回滚事务...,错误的原因:"+e.getMessage());
    }

//    @After("pointcut()")
    public void close(){
        System.out.println("关闭资源...");
    }

    //搞了一个ProceedingJoinPoint(连接点对象)
    @Around("pointcut()")
    public void around(ProceedingJoinPoint joinPoint){
        System.out.println(joinPoint.getArgs()); //参数
        System.out.println(joinPoint.getSignature()); //方法签名(这个方法的所有信息)
        System.out.println(joinPoint.getTarget().getClass()); //真实主题角色
        System.out.println(joinPoint.getThis().getClass()); //代理主题角色
        try {
            begin();
            joinPoint.proceed(); //执行对应的方法
            commit();
        } catch (Throwable e) {
            rollback(e);
            e.printStackTrace();
        } finally {
            close();
        }
    }

}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值