Spring是整合多个框架的主流架构;
Spring有两个目标,一是让现有技术更易于使用,二是养成良好的编程习惯;
AOP:面向切面编程
IoC:控制反转
DI:依赖注入

一、实现配置文件输入什么,控制台输出什么

首先创建一个java工程,Spring42;1、新建lib文件夹,引入jar包;2、创建源文件引入log4j和applicationContext;3、xml引入头文件
applicationContext:

  1. 头文件
  2. <?xml version="1.0" encoding="UTF-8"?>
  3. <beans xmlns="http://www.springframework.org/schema/beans"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xmlns:aop="http://www.springframework.org/schema/aop"
  6. xmlns:p="http://www.springframework.org/schema/p"
  7. xmlns:tx="http://www.springframework.org/schema/tx"
  8. xmlns:context="http://www.springframework.org/schema/context"
  9. xsi:schemaLocation="http://www.springframework.org/schema/beans
  10. http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
  11. http://www.springframework.org/schema/context
  12. http://www.springframework.org/schema/context/spring-context-3.2.xsd
  13. http://www.springframework.org/schema/tx
  14. http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
  15. http://www.springframework.org/schema/aop
  16. http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
  17. </beans>

4、建立helloSpring包,建立HelloSpring类
5、在applicationContext中编写配置文件
applicationContext

  1. <!-- name定义小名,测试时候getBean小名,也能执行 -->
  2. <bean id="hello" class="cn.bdqn.ioc.helloSpring.HelloSpring" name="h1,h2,h3">
  3. <!-- 注入 java反射动态获取的set方法,设置属性519-->
  4. <property name="who">
  5. <value>韩梅梅</value>
  6. </property>
  7. </bean>

HelloSpring:

  1. package cn.bdqn.ioc.helloSpring;
  2. public class HelloSpring {
  3. private String who;
  4. public void print(){
  5. System.out.println("hello:"+getWho());
  6. }
  7. public String getWho() {
  8. return who;
  9. }
  10. public void setWho(String who) {
  11. this.who = who;
  12. }
  13. }

HelloSpringTest:

  1. package cn.bdqn.ioc.helloSpring;
  2. import org.junit.Test;
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;
  5. public class HelloSpringTest {
  6. @Test
  7. public void test1(){
  8. //1.加载Spring的配置文件,实例化Spring的上下文,此处就是控制权的反转
  9. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  10. //2.通过getBean的方法来获取指定<Bean>中id的实例
  11. HelloSpring hs = (HelloSpring)context.getBean("h3");
  12. hs.print();
  13. }
  14. }

以上代码实现控制反转输出hello,韩梅梅

二、什么是控制反转和依赖注入?

  1. IoC是什么?IoC(Inversion of Control) – 控制反转。它不是一种技术,而是一种思想。要理解什么是控制反转。那么我们就要理解“是谁控制谁呢,为什么是反转呢”。
    是谁控制谁:在传统的Java SE程序设计,我们要使用对象要在对象内通过new来创建,即应用程序主动创建依赖对象。而IoC是一个专门创建依赖对象的容器。即容器控制对象。
    为什么是反转:因为IoC帮我们创建并注入依赖对象,对象只是被动地接受依赖对象(传统的是在对象内通过new来主动地创建依赖对象),所以是反转。即从主动获取依赖对象到被动接受依赖对象的反转!
    2. DI是什么?
    DI(Dependency Injection) – 依赖注入。在程序运行期间,容器动态地将依赖关系注入到组件中。要更好地了解DI,我们需要理解以下几点:
    1、谁依赖谁:应用程序依赖于IoC容器;
    2、为什么依赖:应用程序需要IoC容器提供外部资源;
    3、谁注入谁:IoC容器向应用程序注入;
    4、注入什么:IoC向应用程序注入外部资源,数据等。

  2. 两者什么关系?
    IoC和DI其实是同一概念的不同描述。由于IoC(控制反转)不好了解,所以在2004年,Martin Fowler给出了一个新的名称:“依赖注入”。“依赖注入”可以让人们更好地关注到依赖对象和注入这两个重要的东西。

    三、练习,输出A说111,B说222

    applicationContext:

    1. <bean id="zhangga" class="cn.bdqn.ioc.helloSpring.LianXiSpring">
    2. <!-- 注入 java反射动态获取的set方法,设置属性519-->
    3. <property name="who">
    4. <value>张嘎</value>
    5. </property>
    6. <property name="say">
    7. <value>111</value>
    8. </property>
    9. </bean>
    10. <bean id="Rod" class="cn.bdqn.ioc.helloSpring.LianXiSpring">
    11. <!-- 注入 java反射动态获取的set方法,设置属性519-->
    12. <property name="who">
    13. <value>Rod</value>
    14. </property>
    15. <property name="say">
    16. <value>222</value>
    17. </property>
    18. </bean>

    LianXiSpring: ```java package cn.bdqn.ioc.helloSpring;

public class LianXiSpring { private String who; private String say;

  1. public void print(){
  2. System.out.println(getWho()+"说"+getSay());
  3. }
  4. public String getWho() {
  5. return who;
  6. }
  7. public void setWho(String who) {
  8. this.who = who;
  9. }
  10. public String getSay() {
  11. return say;
  12. }
  13. public void setSay(String say) {
  14. this.say = say;
  15. }

}

  1. Test
  2. ```java
  3. package cn.bdqn.ioc.helloSpring;
  4. import org.junit.Test;
  5. import org.springframework.context.ApplicationContext;
  6. import org.springframework.context.support.ClassPathXmlApplicationContext;
  7. public class LianXiTest {
  8. @Test
  9. public void test1(){
  10. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  11. LianXiSpring zhang = (LianXiSpring)context.getBean("zhangga");
  12. LianXiSpring Rod = (LianXiSpring)context.getBean("Rod");
  13. zhang.print();
  14. Rod.print();
  15. }
  16. }

四、认识AOP

1、AOP是面向切面编程,是面向对象的有益补充
2、切面:这些穿插在既定业务中的操作就是所谓的“横切逻辑”
3、面向切面编程:简单地说是在不改变原有程序的基础上为代码段增加新的功能,对其进行增强处理。设计思想来源于代理模式;
4、增强处理就是在方法前后增加输出

5、关键词

切面:Aspect—横切关注点
连接点:JoinPoint—-写增强的参数,具体执行点
增强处理:Advice——-切面在某个特定连接点上执行的代码逻辑
切入点:Pointcut——-对连接点的特征进行描述
目标对象:Target object——-被一个或多个切面增强的对象,即被增强对象
AOP代理:AOPproxy—-由AOP框架所创建的对象,实现执行增强处理方法等功能
织入:Weaving——-将增强处理连接到应用程序中的类型或对象上的过程

6、前置增强

(1)、创建service和dao包,分别创建Impl接口
(2)、在UserServiceImpl下,建立属性,再去Spring IOC注入
(3)、注入和在addUser前后插入日志信息,建立logger包和MyLogger类

  1. applicationContext
  2. <bean id="userDao" class="cn.bdqn.aop.dao.Impl.UserDaoImpl"></bean>
  3. <bean id="userService" class="cn.bdqn.aop.service.Impl.UserServiceImpl">
  4. <!-- name属性名 ref对象519-->
  5. <property name="userDao" ref="userDao"></property>
  6. </bean>
  7. <!-- 前后插入日志 519-->
  8. <bean id="myLogger" class="cn.bdqn.aop.logger.MyLogger"></bean>
  9. <aop:config>
  10. <!-- 定义切点 -->
  11. <aop:pointcut expression="execution(* cn.bdqn.aop.service..*.*(..))" id="pointcut"/>
  12. <!-- 定义切面(切面等于切点加上增强方法) -->
  13. <aop:aspect ref="myLogger">
  14. <!-- 增强方式(前置,后置) -->
  15. <!-- 前置增强 ,此处的方法名和myLogger中匹配的上就行-->
  16. <aop:before method="before" pointcut-ref="pointcut"/>
  17. </aop:aspect>
  18. </aop:config>
  1. //UserDao
  2. package cn.bdqn.aop.dao;
  3. public interface UserDao {
  4. public void addUser();
  5. }
  6. //UserDaoImpl
  7. package cn.bdqn.aop.dao.Impl;
  8. import cn.bdqn.aop.dao.UserDao;
  9. public class UserDaoImpl implements UserDao{
  10. public void addUser(){
  11. System.out.println("---添加用户---");
  12. }
  13. }
  14. //UserService
  15. package cn.bdqn.aop.service;
  16. public interface UserService {
  17. public void addUser();
  18. }
  19. //UserServiceImpl
  20. package cn.bdqn.aop.service.Impl;
  21. import cn.bdqn.aop.dao.UserDao;
  22. import cn.bdqn.aop.service.UserService;
  23. public class UserServiceImpl implements UserService{
  24. //userDao 通过Spring IOC注入
  25. private UserDao userDao;
  26. public UserDao getUserDao() {
  27. return userDao;
  28. }
  29. public void setUserDao(UserDao userDao) {
  30. this.userDao = userDao;
  31. }
  32. //调用dao层的addUser
  33. public void addUser(){
  34. userDao.addUser();
  35. }
  36. }
  37. //MyLogger类
  38. package cn.bdqn.aop.logger;
  39. import org.apache.log4j.Logger;
  40. import org.aspectj.lang.JoinPoint;
  41. public class MyLogger {
  42. //日志输出
  43. Logger log = Logger.getLogger(MyLogger.class);
  44. //定义代理类---applicationContext.xml
  45. //前置增强 JoinPoint连接点
  46. public void before(JoinPoint jp){
  47. //System.out.println("前置增强");
  48. log.info("调用的"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法");
  49. }
  50. }
  51. //aopTest
  52. package cn.bdqn.aop;
  53. import org.junit.Test;
  54. import org.springframework.context.ApplicationContext;
  55. import org.springframework.context.support.ClassPathXmlApplicationContext;
  56. import cn.bdqn.aop.service.UserService;
  57. public class UserTest {
  58. @Test
  59. public void addUser(){
  60. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  61. UserService us = (UserService)context.getBean("userService");
  62. us.addUser();
  63. }
  64. }

以上则是增强处理

五、代理模式

首先,AOP的底层原理就是java的动态代理机制
有两种动态代理机制1,jdk动态代理;2,cglib动态代理
各有优势:CGLIB 1.需要依赖于第三方jar包
2.不依赖目标类的接口

JDK
1.不需要依赖于第三方jar包
2.目标类必须有相应的接口

执行效率:jdk.6之后,jdk动态代理效率>cglib动态代理
SpringAOP 在目标类有实现接口的时候默认使用是jdk代理,没有实现接口使用cglib;
代码分别实现:
首先在aop下创建代理proxy包
其次创建代理类jdkProxy包—>JDKProxy类;目标类:UserDaoImpl;写完Impl再写代理类
最后测试;
CGLIBProxy的测试方法和上面相同
image.png

Jdk代理类

  1. package cn.bdqn.aop.proxy.jdkProxy;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. import java.util.Arrays;
  6. //jdk实现方式 代理类--->实现java反射下的接口,可以看成是中介
  7. public class JDKProxy implements InvocationHandler{
  8. //目标对象---->代理类及方法与目标类及方法建立关联关系
  9. private Object target;
  10. //创建代理类 返回代理对象,参数是目标对象
  11. public Object newProxy(Object obj){
  12. //1.给目标对象赋值
  13. this.target = obj;
  14. //2.通过目标对象获取类加载参数,通过java反射获得
  15. ClassLoader loader = target.getClass().getClassLoader();
  16. //3.通过目标对象获取接口 通过java反射获取
  17. Class<?>[] interfaces = target.getClass().getInterfaces();
  18. //4.最后通过类加载参数和接口初始化代理类
  19. return Proxy.newProxyInstance(loader, interfaces, this);
  20. }
  21. //代理对象想要调用目标方法,所执行的方法名叫invoke
  22. @Override
  23. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  24. // invoke
  25. check();
  26. //修改目标方法的参数;传来的参数是李四,在中间执行代码修改,实现输出的是王五
  27. System.out.println(Arrays.toString(args));
  28. if(args[0].toString().equals("李四")){
  29. args[0] = "王五";
  30. }
  31. //method执行目标方法
  32. Object result = method.invoke(target, args);
  33. //修改返回值
  34. result = 100;
  35. return result;
  36. }
  37. private void check(){
  38. //前置增强
  39. System.out.println("---执行检查---");
  40. }
  41. }

UserDaoImpl:

  1. package cn.bdqn.aop.proxy.dao.Impl;
  2. import cn.bdqn.aop.proxy.dao.UserDao;
  3. //目标类
  4. public class UserDaoImpl implements UserDao{
  5. public int addUser(String userName,int age){
  6. System.out.println("添加用户,姓名:"+userName+"年龄:"+age);
  7. return 1;
  8. }
  9. }
  10. 别忘记抽接口,抽到UserDao

Test:

  1. package cn.bdqn.aop.proxy.jdkProxy;
  2. import cn.bdqn.aop.proxy.dao.UserDao;
  3. import cn.bdqn.aop.proxy.dao.Impl.UserDaoImpl;
  4. public class Test {
  5. public static void main(String[] args) {
  6. //1.创建目标对象
  7. UserDaoImpl udi = new UserDaoImpl();
  8. //原来的执行路径
  9. //udi.addUser("张三", 18);
  10. //2.创建代理类并且初始化代理对象
  11. JDKProxy jdkp = new JDKProxy();
  12. UserDao udiProxy = (UserDao)jdkp.newProxy(udi);//传目标对象,建立关联关系
  13. //3.调用目标方法
  14. int i = udiProxy.addUser("李四", 20);
  15. System.out.println(i);
  16. }
  17. }

CGLIBProxy代理:

  1. package cn.bdqn.aop.proxy.cglibProxy;
  2. import java.lang.reflect.Method;
  3. import org.springframework.cglib.proxy.Enhancer;
  4. import org.springframework.cglib.proxy.MethodInterceptor;
  5. import org.springframework.cglib.proxy.MethodProxy;
  6. /**
  7. * CGLIB
  8. * 1.需要依赖于第三方jar包
  9. * 2.不依赖目标类的接口
  10. *
  11. * JDK
  12. * 1.不需要依赖于第三方jar包
  13. * 2.目标类必须有相应的接口
  14. *
  15. * 执行效率:jdk.6之后,jdk动态代理效率>cglib动态代理
  16. * SpringAOP 在目标类有实现接口的时候默认使用是jdk代理,没有实现接口使用cglib;
  17. *
  18. */
  19. //cglib代理类
  20. public class CGLIBProxy implements MethodInterceptor{
  21. private Object target;
  22. public Object newProxy(Object obj){
  23. this.target = obj;
  24. //创建增强类
  25. Enhancer enhancher = new Enhancer();
  26. //设置生成代理类的父类为传入的目标类
  27. enhancher.setSuperclass(target.getClass());
  28. //设置回调方法为当前的对象;拦截器的回调方法
  29. enhancher.setCallback(this);
  30. //返回动态代理对象
  31. return enhancher.create();
  32. }
  33. @Override
  34. public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
  35. // TODO Auto-generated method stub
  36. check();
  37. Object result = arg1.invoke(target, arg2);
  38. return result;
  39. }
  40. //前置增强
  41. private void check(){
  42. System.out.println("cglib---执行检查--");
  43. }
  44. }

目标类UserDaoImpl:

不变,和jdk用法一样

Test:

package cn.bdqn.aop.proxy.cglibProxy;

import cn.bdqn.aop.proxy.dao.Impl.UserDaoImpl;

public class Test {

    public static void main(String[] args) {
        //创建目标类
        UserDaoImpl udi = new UserDaoImpl();
        //创建代理类
        CGLIBProxy cglib = new CGLIBProxy();
        //目标对象放进去
        UserDaoImpl proxy = (UserDaoImpl)cglib.newProxy(udi);
        int i = proxy.addUser("李四", 18);
        System.out.println(i);

    }

}

六、IoC和AOP扩展

1、注入的方式有三种

(1)、设置值注入

设置值注入就是HelloSpring中没有构造方法,实现输出hello,韩梅梅

(2)、构造注入

以HelloSpring 为例,在里面加入无参和有参构造方法,其他不变
在applicationcontext中重新配置hello后面输出要加的文字
输出hello,李雷

HelloSpring:
package cn.bdqn.ioc.helloSpring;
/*
 * 1、设置值注入;依赖于属性的set方法
 * 2、构造注入;依赖于构造方法
 */
public class HelloSpring {
    private String who;

    public HelloSpring(){

    }
    public HelloSpring(String who){
        this.who = who;
    }
    public void print(){
        System.out.println("hello:"+getWho());
    }

    public String getWho() {
        return who;
    }

    public void setWho(String who) {
        this.who = who;
    }

}
配置文件applicationContext中:
<!-- 第二种注入方式:构造注入521 -->
    <bean id="hello2" class="cn.bdqn.ioc.helloSpring.HelloSpring" >
        <constructor-arg>
            <value>李雷</value>
        </constructor-arg>
    </bean>


测试不变:
package cn.bdqn.ioc.helloSpring;

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

public class HelloSpringTest {
    @Test
    public void test1(){
        //1.加载Spring的配置文件,实例化Spring的上下文,此处就是控制权的反转
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2.通过getBean的方法来获取指定<Bean>中id的实例
        HelloSpring hs = (HelloSpring)context.getBean("hello");
        hs.print();
    }
}

另一实现,使用构造注入实现谁说了什么

输出lili说111

//LianXiSpring中也是加入有参和无参构造方法
package cn.bdqn.ioc.helloSpring;

public class LianXiSpring {
    private String who;
    private String say;

    //加构造方法是为了构造注入
    public LianXiSpring(){

    }
    public LianXiSpring(String who,String say){
        this.say = say;
        this.who = who;
    }
    public void print(){
        System.out.println(getWho()+"说"+getSay());
    }
    public String getWho() {
        return who;
    }
    public void setWho(String who) {
        this.who = who;
    }
    public String getSay() {
        return say;
    }
    public void setSay(String say) {
        this.say = say;
    }
}

配置文件中重新配置
<!-- 构造注入实现谁说了什么 -->
    <bean id="lili" class="cn.bdqn.ioc.helloSpring.LianXiSpring">
        <constructor-arg index="0">
            <value>莉莉</value>
        </constructor-arg>
        <constructor-arg index="1">
            <value>111</value>
        </constructor-arg>
    </bean>

测试
@Test
public void test2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        LianXiSpring lili = (LianXiSpring)context.getBean("lili");
        lili.print();

    }

(3)、p:命名空间注入


首先建pojo包,建立学生类,配置,测试 java 首先,学生类:设置三个属性,姓名,年龄,英文名,提供get/set方法 package cn.bdqn.ioc.pojo; public class Student { private String name; private int age; private String englishName; //提供get/set方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getEnglishName() { return englishName; } public void setEnglishName(String englishName) { this.englishName = englishName; } } 配置文件,applicationContext <bean id="student" class="cn.bdqn.ioc.pojo.Student" p:name="张三" p:age="18"> <property name="englishName"> <value><![CDATA[j&k]]></value> </property> </bean> 测试: package cn.bdqn.ioc.helloSpring; import org.junit.Test; import cn.bdqn.ioc.pojo.Student; public class StudentTest { @Test public void pTest(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Student stu = (Student)context.getBean("student"); //p空间注入 System.out.println(stu.getName()+"---"+stu.getAge()); System.out.println(stu.getEnglishName()); } ## 2、P命名空间下注入不同的数据类型 例如在学生类总注入其他类 ### (1)、注入Bean类型 配置的时候有三种方法 #### ①、local是在当前文件找hello这个指定id的bean;—输出hello, #### ②、bean用法表示在拆分后所有Spring中的配置文件中整体查找指定id的bean—输出hello, #### ③、内部bean 输出hello,内部bean—输出hello,内部Bean ```java 首先学生类中:设置Bean类型属性,提供get/set方法 package cn.bdqn.ioc.pojo; import cn.bdqn.ioc.helloSpring.HelloSpring; public class Student { //bean类型注入 private HelloSpring hs; public HelloSpring getHs() { return hs; } public void setHs(HelloSpring hs) { this.hs = hs; } } 配置文件中:
    <property name="hs">
        <!--  1、local是在当前文件找hello这个指定id的bean;
              2、bean用法表示在拆分后所有Spring中的配置文件中整体查找指定id的bean
        <ref bean="hello"/>
        -->
        <!--  
        <ref local="hello"/>
        -->
        <!-- 3、内部bean 输出hello,内部bean-->
        <bean class="cn.bdqn.ioc.helloSpring.HelloSpring">
            <property name="who">
                <value>内部bean</value>
            </property>
        </bean>
    </property>

测试:StudentTest public class StudentTest { @Test public void pTest(){ //bean类型注入 stu.getHs().print(); }

}

<a name="GL47R"></a>
### (2)、集合注入List/Set/Map/属性集合Properties
```java
学生类
public class Student {
    //集合注入
    private List<String> likeList;
    //集合注入
    private Set<String> likeSet;
    //集合注入
    private Map<String,String> likeMap;
    //集合注入--属性集合
    private Properties prop;

    public Properties getProp() {
        return prop;
    }
    public void setProp(Properties prop) {
        this.prop = prop;
    }
    public Map<String, String> getLikeMap() {
        return likeMap;
    }
    public void setLikeMap(Map<String, String> likeMap) {
        this.likeMap = likeMap;
    }
    public Set<String> getLikeSet() {
        return likeSet;
    }
    public void setLikeSet(Set<String> likeSet) {
        this.likeSet = likeSet;
    }
    public List<String> getLikeList() {
        return likeList;
    }
    public void setLikeList(List<String> likeList) {
        this.likeList = likeList;
    }
}

配置文件
<bean id="student" class="cn.bdqn.ioc.pojo.Student" p:name="张三" p:age="18">

        <!-- 集合注入 -->
        <property name="likeList">
            <list>
                <value>足球</value>
                <value>篮球</value>
                <value>羽毛球</value>
            </list>
        </property>
        <property name="likeSet">
            <set>
                <value>游泳</value>
                <value>健身</value>
            </set>
        </property>
        <property name="likeMap">
            <map>
                <entry>
                    <key>
                        <value>football</value>
                    </key>
                    <value>足球</value>
                </entry>
                <entry>
                    <key>
                        <value>basketball</value>
                    </key>
                    <value>篮球</value>
                </entry>
            </map>

        </property>
        <!-- Properties集合注入 -->
        <property name="prop">
            <props>
                <prop key="football">足球</prop>
                <prop key="basketball">蓝球</prop>
            </props>
        </property>
</bean>

测试StudentTest:
public class StudentTest {
    @Test
    public void pTest(){
        //list注入
        System.out.println("-------List注入---------");
        for (String s1 : stu.getLikeList()) {
            System.out.print(s1+",");
        }
        //set注入
        System.out.println();
        System.out.println("-------Set注入---------");
        for (String s1 : stu.getLikeSet()) {
            System.out.print(s1+",");
        }
        //Map注入
        System.out.println();
        System.out.println("-------Map注入---------");
        Map<String,String> map = stu.getLikeMap();
        for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println(entry);
        }

        //Properties注入
        System.out.println();
        System.out.println("-------Properties注入---------");
        Properties prop = stu.getProp();
        Set<Entry<Object, Object>> propSet =prop.entrySet();
        for (Entry<Object, Object> entry : propSet) {
            System.out.println(entry.getKey()+"---"+entry.getValue());
        }
    }
}

(3)、注入空值和null值

package cn.bdqn.ioc.pojo;
//521、p命名空间注入
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import cn.bdqn.ioc.helloSpring.HelloSpring;

public class Student {
    private String name;
    private int age;
    private String englishName;
    //bean类型注入
    private HelloSpring hs;
    //集合注入
    private List<String> likeList;
    //集合注入
    private Set<String> likeSet;
    //集合注入
    private Map<String,String> likeMap;
    //集合注入--属性集合
    private Properties prop;
    //注入null或者空值
    private String n1;//n1表示null
    private String n2;//n2表示空

    public String getN1() {
        return n1;
    }
    public void setN1(String n1) {
        this.n1 = n1;
    }
    public String getN2() {
        return n2;
    }
    public void setN2(String n2) {
        this.n2 = n2;
    }
    public Properties getProp() {
        return prop;
    }
    public void setProp(Properties prop) {
        this.prop = prop;
    }
    public Map<String, String> getLikeMap() {
        return likeMap;
    }
    public void setLikeMap(Map<String, String> likeMap) {
        this.likeMap = likeMap;
    }
    public Set<String> getLikeSet() {
        return likeSet;
    }
    public void setLikeSet(Set<String> likeSet) {
        this.likeSet = likeSet;
    }
    public List<String> getLikeList() {
        return likeList;
    }
    public void setLikeList(List<String> likeList) {
        this.likeList = likeList;
    }
    public HelloSpring getHs() {
        return hs;
    }
    public void setHs(HelloSpring hs) {
        this.hs = hs;
    }
    //提供get/set方法
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getEnglishName() {
        return englishName;
    }
    public void setEnglishName(String englishName) {
        this.englishName = englishName;
    }

}

配置文件:
<!--第三种注入方式, p命名空间注入521  value中有特殊字符,需要转义  输出张三18和张三的英文名j&k-->
    <bean id="student" class="cn.bdqn.ioc.pojo.Student" p:name="张三" p:age="18">
        <property name="englishName">
            <value><![CDATA[j&k]]></value>
        </property>
        <!-- 注入bean类型  输出hello-->
        <property name="hs">
            <!--  1、local是在当前文件找hello这个指定id的bean;
                  2、bean用法表示在拆分后所有Spring中的配置文件中整体查找指定id的bean
            <ref bean="hello"/>
            -->
            <!--  
            <ref local="hello"/>
            -->
            <!-- 3、内部bean 输出hello,内部bean-->
            <bean class="cn.bdqn.ioc.helloSpring.HelloSpring">
                <property name="who">
                    <value>内部bean</value>
                </property>
            </bean>
        </property>

        <!-- 集合注入 -->
        <property name="likeList">
            <list>
                <value>足球</value>
                <value>篮球</value>
                <value>羽毛球</value>
            </list>
        </property>
        <property name="likeSet">
            <set>
                <value>游泳</value>
                <value>健身</value>
            </set>
        </property>
        <property name="likeMap">
            <map>
                <entry>
                    <key>
                        <value>football</value>
                    </key>
                    <value>足球</value>
                </entry>
                <entry>
                    <key>
                        <value>basketball</value>
                    </key>
                    <value>篮球</value>
                </entry>
            </map>

        </property>
        <!-- Properties集合注入 -->
        <property name="prop">
            <props>
                <prop key="football">足球</prop>
                <prop key="basketball">蓝球</prop>
            </props>
        </property>
        <!-- 注入null或者空值 -->
        <property name="n1">
            <null/>
        </property>
        <property name="n2">
            <value></value>
        </property>
    </bean>

测试:
package cn.bdqn.ioc.helloSpring;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;

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

import cn.bdqn.ioc.pojo.Student;

public class StudentTest {
    @Test
    public void pTest(){
        ApplicationContext context = 
                new ClassPathXmlApplicationContext("applicationContext.xml");
        Student stu = (Student)context.getBean("student");
        //p空间注入
        System.out.println(stu.getName()+"---"+stu.getAge());
        System.out.println(stu.getEnglishName());

        //bean类型注入
        stu.getHs().print();

        //list注入
        System.out.println("-------List注入---------");
        for (String s1 : stu.getLikeList()) {
            System.out.print(s1+",");
        }
        //set注入
        System.out.println();
        System.out.println("-------Set注入---------");
        for (String s1 : stu.getLikeSet()) {
            System.out.print(s1+",");
        }
        //Map注入
        System.out.println();
        System.out.println("-------Map注入---------");
        Map<String,String> map = stu.getLikeMap();
        for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println(entry);
        }

        //Properties注入
        System.out.println();
        System.out.println("-------Properties注入---------");
        Properties prop = stu.getProp();
        Set<Entry<Object, Object>> propSet =prop.entrySet();
        for (Entry<Object, Object> entry : propSet) {
            System.out.println(entry.getKey()+"---"+entry.getValue());
        }

        //注入null或者空值
        System.out.println("n1="+stu.getN1());
        System.out.println("n2="+stu.getN2());
    }
}

3、AOP扩展

(1)、前置增强 before

初识AOP写了前置增强

(2)、后置增强 afterReturning

首先、在aop—>dao—>UserDaoImpl中写入一个方法,抽接口,再收到Service相关中
其次,修改配置文件中插入日志的相关配置,修改切点
再在UserTest测试中,添加后置增强测试输出
再在配置文件内的前后插入日志中添加后置增强
最后在MyLogger中添加各种增强方法

image.png
1、此处的UserTest中,传入的id为1的时候,输出的是“张三”;
2、获得参数:MyLogger中://前置增强打印参数 Object[] args = jp.getArgs();log.info(“参数=”+Arrays.toString(args));
在UserTest中,运行getUserNameById方法,输出-参数=【1】
3、修改参数://前置增强无法修改参数,只能在环绕增强修改
4、进行后置操作,运行UserTest中的getUserNameById方法,实现在张三上面输出-后置增强,返回值=张三
5、修改参数,在MyLogger代理类中,写入环绕增强,先获取参数,再修改参数,args[0] = 100;;会将100传入id,实现输出 -后置增强,返回值=大聪明;下面输出 大聪明;
6、修改返回结果,再本来输出的大聪明后面加上‘真棒!’;
//修改返回结果 result = result+”真棒!”;
log.info(“后置增强,返回值=”+result); return result;

UserDaoImpl:
package cn.bdqn.aop.dao.Impl;

import cn.bdqn.aop.dao.UserDao;

public class UserDaoImpl implements UserDao{
    public void addUser(){
        System.out.println("---添加用户---");
    }
    //后置增强用到
    public String getUserNameById(int id){
        //伪代码
        if(id == 1){
            return "张三";
        }else if(id == 2){
            return "李四";
        }else{
            return "大聪明";
        }
    }
}

UserDao接口
package cn.bdqn.aop.dao;

public interface UserDao {
    public void addUser();
    public String getUserNameById(int id);
}

UserService接口:
package cn.bdqn.aop.service;

public interface UserService {
    public void addUser();
    public String getUserNameById(int id);
}

UserServiceImpl目标类
package cn.bdqn.aop.service.Impl;

import cn.bdqn.aop.dao.UserDao;
import cn.bdqn.aop.service.UserService;
//目标类---》实例化 ---》目标对象---》最终想执行目标方法addUSer(),
//执行方法之前想干别的事,还不行修改本处的代码/代理对象去调用执行目标方法
public class UserServiceImpl implements UserService{
    //userDao 通过Spring IOC注入
    private UserDao userDao;

    public UserServiceImpl(){

    }
    public UserServiceImpl(UserDao userDao){
        this.userDao = userDao;
    }
    public UserDao getUserDao() {
        return userDao;
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    //调用dao层的addUser
    public void addUser(){
        userDao.addUser();
    }
    //后置增强用到
    public String getUserNameById(int id){
        return userDao.getUserNameById(id);
    }
}

配置文件中修改切点
<!-- 定义切点 521修改,将括号前面的*换成UserDaoImpl中的方法名-->
        <aop:pointcut expression="execution(* cn.bdqn.aop.service..*.getUserNameById(..))" id="pointcut"/>


测试中添加后置增强测试;只这一次,之后的增强方法都适用
package cn.bdqn.aop;

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

import cn.bdqn.aop.service.UserService;

public class UserTest {
    @Test
    public void addUser(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService us = (UserService)context.getBean("userService");
        us.addUser();
    }
    //后置增强测试,通过获得名字方法传入id,获得姓名
    @Test
    public void getUserNameById(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService us = (UserService)context.getBean("userService");
        //给下面的方法加前置后置
        String name = us.getUserNameById(1);
        //前置后置完成后才会输出下面的
        System.out.println(name);
    }
}

配置文件中添加后置增强
<!-- 前后插入日志 519-->
    <bean id="myLogger" class="cn.bdqn.aop.logger.MyLogger"></bean>
    <aop:config>
        <!-- 定义切点 521修改,将括号前面的*换成UserDaoImpl中的方法名-->
        <aop:pointcut expression="execution(* cn.bdqn.aop.service..*.getUserNameById(..))" id="pointcut"/>
        <!-- 定义切面(切面等于切点加上增强方法) -->
        <aop:aspect ref="myLogger">
            <!-- 增强方式(前置,后置) -->
            <!-- 前置增强 ,此处的方法名和myLogger中匹配的上就行 -->
            <aop:before method="before" pointcut-ref="pointcut"/>

            <!-- 后置增强 -->
            <aop:after-returning method="afterReturning" returning="result" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>

MyLogger代理类中

package cn.bdqn.aop.logger;

import java.beans.Expression;
import java.util.Arrays;

//代理类--》实例化---》代理对象--》调用执行目标方法,在执行之前完成相应的功能
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class MyLogger {
    //日志输出
    Logger log = Logger.getLogger(MyLogger.class);
    //定义代理类---applicationContext.xml
    //前置增强  JoinPoint连接点
    public void before(JoinPoint jp){
        //System.out.println("前置增强");
        log.info("调用的"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法");
        //前置增强打印参数
        Object[] args = jp.getArgs();
        args[0] = 100;
        //前置增强可以获取参数,修改参数只能在环绕增强
        log.info("参数="+Arrays.toString(args));
    }
    //后置增强
    public void afterReturning(JoinPoint jp,Object result){
        //做完事情要输出什么内容,并获得返回值
        log.info("后置增强,返回值是"+result);
    }

}

(3)、异常增强 afterThrowing

配置文件内加入:
<!-- 异常增强 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut"/>

MyLogger代理类中加入
    //异常增强
    public void afterThrowing(JoinPoint jp,Exception e){
        System.out.println("异常增强"+e.getMessage());

    }

(4)、环绕增强 around

环绕增强可以替代前置,后置,异常,和最终
,代理类中的around方法,不仅可以改变传入的id,还可以改变返回的结果

其他不变,在配置文件中加入环绕增强
<!-- 前后插入日志 519-->
    <bean id="myLogger" class="cn.bdqn.aop.logger.MyLogger"></bean>
    <aop:config>
        <!-- 定义切点 521修改,将括号前面的*换成UserDaoImpl中的方法名-->
        <aop:pointcut expression="execution(* cn.bdqn.aop.service..*.getUserNameById(..))" id="pointcut"/>
        <!-- 定义切面(切面等于切点加上增强方法) -->
        <aop:aspect ref="myLogger">
            <!-- 增强方式(前置,后置) -->
            <!-- 前置增强 ,此处的方法名和myLogger中匹配的上就行
            <aop:before method="before" pointcut-ref="pointcut"/>
            -->
            <!-- 后置增强 
            <aop:after-returning method="afterReturning" returning="result" pointcut-ref="pointcut"/>
            -->
            <!-- 异常增强 -->
            <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut"/>
            <!-- 环绕增强 -->
            <aop:around method="around" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>

MyLogger代理类中加入环绕增强
//环绕增强
    public Object around(ProceedingJoinPoint pjp){
        log.info("调用的"+ pjp.getTarget()+"的"+ pjp.getSignature().getName()+"方法");
        Object[] args = pjp.getArgs();
        log.info("参数="+Arrays.toString(args));
        //修改后的参数,传入id位置,返回结果就是大聪明
        args[0] = 100;
        Object result = null;
        try {
            //执行目标方法
            result = pjp.proceed(args);
        } catch (Throwable e) {
            //这里写代码就是异常增强
            e.printStackTrace();
        }finally{
            //最终增强
        }
        //修改返回结果
        result = result+"真棒!";
        log.info("后置增强,返回值="+result);
        return result;


    }
}

(5)、最终增强 finally

配置文件中加入:
<!-- 最终增强 -->
            <aop:after method="afterLogger" pointcut-ref="pointcut"/>

MyLogger代理类中
//最终增强
public void afterLogger(JoinPoint jp){
    System.out.println(jp.getSignature().getName()+"方法结束执行");
}

七、使用注解实现IoC

1、IoC包下创建一个dao层,

创建Impl和PersonDao;抽接口;回到PersonDaoImpl中加入注解
再去配置文件,配置context:component-scan
再新建PersonTest,测试;

2、如果把注解中的 参数去掉,测试时getBean中传入方法所在类名,首字母小写。

3、注解:

@Component(“personDao”)——组件
@Repository————————用于标注dao类
@Service——————————用于标注业务类
@Controller————————-用于标注控制器(Servlect)下的类

Ioc下的dao层的PersonDaoImpl

package cn.bdqn.ioc.dao.Impl;

import org.springframework.stereotype.Repository;

import cn.bdqn.ioc.dao.PersonDao;

//使用注解实现IoC
//@Repository,相当于在配置文件中声明PersonDao,再去配置文件扫描指定包内的注解,使其生效
//如果注解中参数去掉,测试时getBean中传入方法所在类名,首字母小写;
@Repository
public class PersonDaoImpl implements PersonDao {
    //模拟添加
    public void addPerson(){
        System.out.println("添加人员");
    }
    //抽接口
}

抽接口

package cn.bdqn.ioc.dao;

public interface PersonDao {
    public void addPerson();
}

配置文件
<!-- 扫描指定包内的注解,使其生效   传接口中的地址也可,因为是自动扫描所有的注解523 -->
    <context:component-scan base-package="cn.bdqn"></context:component-scan>

测试
@Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        PersonDao pd = (PersonDao)context.getBean("personDaoImpl");
        pd.addPerson();

    }

4、IoC下创建service包

创建Impl和PersonService接口
Impl中创建Bean类型属性 PersonDao;写一个addPerson的方法,personDao.addPerson();抽接口
配置文件,测试
加入@Service和@Autowired注解,代替配置文件中注入的过程
配置时不需要再重建,可直接在已有基础上,加上Service路径

PersonDaoImpl:

package cn.bdqn.ioc.service.Impl;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import cn.bdqn.ioc.dao.PersonDao;
import cn.bdqn.ioc.service.PersonService;
//@Service代替了Bean的声明
@Service("personService")
public class PersonServiceImpl implements PersonService {
    /*@Autowired默认按照类型进行匹配,Spring提供的注解
     * 如果发现类型相同的有多个,可用@Qualifer("personDaoImpl")进行名称定位,
     * 哪个名称,是PersonDao这个bean的名称
     * @Autowired代替配置文件中注入的过程
     * 
     * @Resource默认按照名称进行匹配;java自带注解,JavaX包下的
     * 如果没有找到相应的名称PersonDao,直接按类型查找
    */
    @Resource
    private PersonDao personDao;
    public void addPerson(){
        personDao.addPerson();
    }
}

抽接口
package cn.bdqn.ioc.service;

public interface PersonService {
    public void addPerson();
}


同上配置,查找路径归于一个cn.bdqn

测试:
@Test
    public void test2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        PersonService pd = (PersonService)context.getBean("personService");
        pd.addPerson();

    }

5、@Autowired和@Resoource注解的区别?

/*@Autowired默认按照类型进行匹配,Spring提供的注解

 * 如果发现类型相同的有多个,可用                                                                     @Qualifer("personDaoImpl")进行名称定位,


哪个名称,是PersonDao这个bean的名称
@Autowired代替配置文件中注入的过程

@Resource默认按照名称进行匹配;java自带注解,JavaX包下的
如果没有找到相应的名称PersonDao,直接按类型查找
/

6、将Autowired换成Resource也好使;配置文件中的查找路径可以直接用cn.bdqn,匹配这个下的所有注解

八、使用注解实现AOP

在aop中创建MyLogger2代理类;加上@Aspect注解
在环绕增强上方加入注解@Around(),去除设置参数和修改结果
调用UserServiceImpl中的addUser方法,查看输出结果是否有“—调用**
最后测试addUser方法