Spring6学习及复习笔记

发布于:2025-05-18 ⋅ 阅读:(16) ⋅ 点赞:(0)

1、快速入门认识

通过编写xml配置文件来创建对象,读取bean标签的id值和class值来创建。

之后再通过对象调用相关的方法(这里实际上用到的是反射机制)

对象会存放到Map集合中

大致反射思路如下:(这里只是模拟,并非真的就这几行实现)

 2、整合log4j2日志框架

引入依赖,创建配置文件log4j2.xml    这样便可自动生成日志

手动写日志:
Logger logger=LoggerFactory.getLogger(testUser.class);
logger.info("手动写日志成功了");

 3、IOC

一、IOC容器

IOC即为控制反转,使用IOC容器管理bean对象,设计出更加松耦合的程序

用它来管理对象的实例化和初始化,以及对象间的依赖关系。

对象用Map集合存放

DI,即为依赖注入,实现了控制反转这一思想

一般使用set或构造注入

二、XML管理bean

1、获取bean

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

ApplicationContext context=new ClassPathXmlApplicationContext(bean.xml);

User user1=(User)context.getBean("user");//根据id获取bean

User user2=(User)context.getBean(User.class);//根据类型获取bean

User user3=(User)context.getBean("user",User.class);//根据id和类型获取bean

注意,获取时指定类型bean只能有一个,如果同一个类有多个bean会报错。

一般都只根据id获取,确保每个bean的id不一样 

这里还可以配置接口的实现类,然后获取对象时通过接口的类名来获取,但实现类必须唯一。

2、setter注入

确保属性有set方法和构造方法

//set注入

<bean id="book"  class="com.book">

<property name="name"  value="图书名称"></property>  

<property name="author"  value="图书作者"></property>

</bean>  

//构造器注入

<bean id="book1"  class="com.book">

<constructor-arg  name="name"   value="图书名称"></constructor-arg>

<constructor-arg  name="author"   value="图书作者"></constructor-arg>

</bean>  

特殊值处理 

  1. 字面量赋值。String  a="33a"
  2. null。    使用标签<null/>
  3. xml实体。     对字符转义   <  :&lt     >:&gt
  4. CDATA节       用来写特殊符号
3、对象类型赋值

//引入外部bean

<bean id="dept"   class="com.dept">

<property  name="dname"   value="部门属性"></property>

</bean>

<bean id="emp"   class="com.emp">

<property name="ename"  value="员工名字"></property>  

<property name="age"  value="50"></property>

<property name="dept"  ref="dept"></property>

</bean>

 //内部bean

<bean id="emp2"   class="com.emp">

<property name="ename"  value="员工名字"></property>  

<property name="age"  value="50"></property>

   <property name="dept" >     

           <bean id="dept2"   class="com.dept">

                <property  name="dname"   value="部门属性"></property>

            </bean>

    </property>

</bean>

 //级联属性赋值(少用)

<bean id="dept3"   class="com.dept">

</bean>        

<bean id="emp3"   class="com.emp">

<property name="ename"  value="员工名字"></property>  

<property name="age"  value="50"></property>

<property name="dept"  ref="dept"></property>

<property  name="dept.dname"   value="部门属性"></property>

</bean>

4、数组类型属性注入

<bean id="dept"   class="com.dept">

<property  name="dname"   value="部门属性"></property>

</bean>

<bean id="emp"   class="com.emp">

<property name="ename"  value="员工名字"></property>  

<property name="age"  value="50"></property>

<property name="dept"  ref="dept"></property>

<property name="hobby"  >

     <array>

     <value>抽烟</value>

    <value>喝酒</value>

     <value>烫头</value>

     </array>

</property>

</bean>

5、集合类型属性注入

 List集合属性注入

<bean id="dept"   class="com.dept">

<property  name="dname"   value="部门属性"></property>

<property  name="empList">

     <list>

       <ref  bean="emp2"></ref>

      </list>

</property>

</bean>

Map集合属性注入 

<bean id="dept"   class="com.dept">

<property  name="dname"   value="部门属性"></property>

<property  name="empMap">

     <map>

       <entry>

         <key>

            <value>1</value>

          </key>

         <ref bean="emp2"></ref>

       </entry>

   </map>

</property>

</bean>

引用集合类型的bean,使用util

 <property  name="empList"  ref="empList"></property>

<util:list  id=empList>

     //里面写集合

       <ref  bean="emp2"></ref>

</util:list>

6、引入外部属性文件

引用依赖,再创建properties文件。

7、bean的作用域

8、bean的生命周期

 

<bean  id="user"  class="com.User"  init-method="initMethod"  destory-method="destoryMethod">

<property  name="name"   value="名字"></property> 

</bean>

销毁用context.close()

//后置处理器使用,要实现BeanPostProcess接口 

9、FactoryBean

 ​​​​​​配置MyFactoryBean会生成User对象

 10、自动注入

三、注解管理bean

1、注解初识

不提供value默认找首字母小写的同类名id

2、Autowired

默认根据类型匹配

@AutoWired                    //属性注入

private    Service   service;

@Autowired                   //set方法注入

public  void setUserController(UserService   userservice) 

{   this.userservice=userservice;}

 @Autowired                   //构造方法注入

public  UserController(UserService   userservice) 

{   this.userservice=userservice;}

                //形参注入

public  UserController( @Autowired   UserService   userservice) 

{   this.userservice=userservice;}

 @AutoWired               

@Qualifier(value="userServiceFirst")        //联合使用,根据名称进行注入

private    Service   service;

3、Resource

 

4、全注解开发

使用配置类来替代配置文件

 四、手写IOC

1、Java反射

Car类

package reflect;

public class Car {
    private String name;
    private int age;
    private String color;


    private void run()
    {
        System.out.println("私有方法run......");
    }
    public Car() {
    }

    public Car(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

    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 getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

TestCar,获取类并实例化对象

package reflect;

import org.junit.Test;

public class TestCar {
    //获取class对象的三种方式
    @Test
    public void test1() throws Exception {
        //方式一:调用运行时类的属性.class
        Class carClass = Car.class;
        System.out.println(carClass);
        //方式二:通过运行时类的对象,调用getClass()
        Class carClass1 = new Car().getClass();
        System.out.println(carClass1);
        //方式三:调用Class的静态方法:forName(String classPath)
        Class carClass2 = Class.forName("reflect.Car");
        System.out.println(carClass2);

        //实例化
        Car car=(Car)carClass.getDeclaredConstructor().newInstance();
        System.out.println(car);


    }
}

获取构造方法,并设置对象参数

@Test
    public void test2() throws Exception {
        Class carClass = Car.class;
        //获取所有构造方法包括private修饰的
        Constructor[] constructors=carClass.getDeclaredConstructors();
        for(Constructor constructor:constructors){
            System.out.println(constructor);
        }

        //    获取指定的构造方法
        Constructor constructor=carClass.getDeclaredConstructor(    String.class,int.class,String.class);
        constructor.setAccessible(true);//解除私有限定
        Car car=(Car)constructor.newInstance("宝马",10,"红色");
        System.out.println(car);
    }

获取属性并设置

@Test
    public void test3() throws Exception {
        //获取所有属性包括private修饰的
        Class carClass = Car.class;
        Car car=(Car)carClass.getDeclaredConstructor().newInstance();
        Field[]  fields=carClass.getDeclaredFields();
        for(Field field:fields){
            if(field.getName().equals("name"))
            {
                field.setAccessible(true);//解除私有限定
                field.set(car,"奔驰");
            }
          //  System.out.println(field);
            System.out.println(car);
         }
    }

获取方法得到返回值

@Test
    public void test4() throws Exception {
        Car car=new Car("奔驰",10,"红色");
        Class carClass = car.getClass();
        Method[] methods=carClass.getDeclaredMethods();
        for(Method method:methods){
            if(method.getName().equals("run"))
            {
                method.setAccessible(true);//解除私有限定
                method.invoke(car);
            }
            else if(method.getName().equals("toString"))
            {
                method.setAccessible(true);//解除私有限定
                String str=(String)method.invoke(car);
                System.out.println(str);
            }
        }
    }
2、手写IOC

创建两个注解,bean和di,分别用于创建对象和注入属性

package com.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Bean {
}
package com.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Di {
}

实现AnnotationApplicationContext

package com.bean;

public interface ApplicationContext {
    Object getBean(Class clazz);
}
package com.bean;

import com.anno.Bean;

import java.io.File;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

public class AnnotationApplicationContext implements ApplicationContext {

    private  Map<Class,Object> beanMap = new HashMap<>();
    private  String rootpath;
    @Override
    public Object getBean(Class clazz) {
        return beanMap.get(clazz);
    }

    public AnnotationApplicationContext(String basepackage)
    {
        //把包名转化为路径名
         String packagepath= basepackage.replaceAll("\\.","\\\\");
         try {
             //获取当前线程的类加载器,然后获取所有资源的路径
             Enumeration<URL> urls=Thread.currentThread().getContextClassLoader().getResources(packagepath);
            //遍历路径
             while (urls.hasMoreElements())
             {
                 //获取路径
                 URL url=urls.nextElement();
                 //解码
                 String FilePath= URLDecoder.decode(url.getFile(),"UTF-8");
                 //获取项目的根路径
                 rootpath=FilePath.substring(0,FilePath.length()-packagepath.length());
                 //加载bean
                 loadBean(new File(FilePath));
             }
         }catch (Exception e)
         {
             e.printStackTrace();
         }

    }
    private void loadBean(File file) throws Exception {
        //如果是文件夹,就进入文件夹
      if(file.isDirectory())
      {
          //获取文件夹下的所有文件
          File[] files=file.listFiles();
          //如果文件夹下没有文件,就返回
          if(files==null||files.length==0)
          {
              return;
          }
          //遍历文件夹下的所有文件
          for (File child:files)
          {
              //如果是文件夹,就递归进入文件夹加载
              if(child.isDirectory())loadBean(child);
              else {
                  //如果是文件,就加载bean
                  //获取类的路径
                  String pathwithclass=child.getAbsolutePath().substring(rootpath.length()-1);
                  //如果是class文件,就加载bean
                  if(pathwithclass.contains(".class"))
                  {
                      //把路径转化为包名
                      String allname=pathwithclass.replaceAll("\\\\",".").replace(".class","");
                      Class<?> clazz=Class.forName(allname);
                      //不是接口
                      if(!clazz.isInterface())
                      {
                          Bean annotation=clazz.getAnnotation(Bean.class);
                          //是bean
                          if(annotation!=null)
                          {
                              Object instance =clazz.getConstructor().newInstance();
                              //是否实现了接口
                              if(clazz.getInterfaces().length>0)
                              {
                                   beanMap.put(clazz.getInterfaces()[0],instance);
                              }else {
                                  beanMap.put(clazz,instance);
                              }
                          }
                      }
                  }

              }
          }
      }
    }
}

实现service和dao的实现类

package com.dao;

import com.anno.Bean;

@Bean
public class UserDaoImpl implements UserDao {
    @Override
    public void add() {
        System.out.println(
                "UserDaoImpl add"
        );
    }
    
}
package com.service;

import com.anno.Bean;
import com.anno.Di;
import com.dao.UserDao;

@Bean
public class UserServiceImpl implements UserService{
   @Di
    private UserDao userDao;

    @Override
    public void add() {
        System.out.println("userservice add");
    }
}

测试:

package com;

import com.bean.AnnotationApplicationContext;
import com.bean.ApplicationContext;
import com.service.UserService;

import java.net.URL;
import java.util.Enumeration;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context=new AnnotationApplicationContext("com");
        UserService userService=(UserService)context.getBean(UserService.class);
        System.out.println(userService);
        userService.add();
    }
}

修改AnnotationApplicationContext代码,增加属性注入 。getbean里增加loadDi()

 private void loadDi()
    {
        //遍历beanMap
        for (Map.Entry<Class,Object> entry:beanMap.entrySet())
        {
            //获取bean的所有属性
            Object obj=entry.getValue();
            //获取对象Class
            Class<?> clazz=obj.getClass();
            //获取对象的所有属性
            Field[] fields=clazz.getDeclaredFields();
            //遍历属性
            for (Field field:fields)
            {
                //判断属性是否有Di注解
                Di annotation=field.getAnnotation(Di.class);
                if(annotation!=null)
                {
                    field.setAccessible(true);
                    //如果有Di注解,就注入属性
                    try {
                        field.set(obj,beanMap.get(field.getType()));
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    }

测试

4、AOP 

一、代理模式

核心代码与日志代码在一起不合理,不利于维护。所以使用代理模式

1、静态代理

再写一个接口的实现类,定义一个核心实现类的对象作为属性,然后同样的方法中去调用,前后增加自己的代码。

但是代码写死了没有具备灵活性。

2、动态代理

public Object getProxy()
   {
      //得到类加载器
      ClassLoader classloader=target.getClasss().getClassLoader();
      //目标对象实现接口的数组形式
      Class<?> interfaces=target.getClass().getInterfaces();
       //设置实现目标方法的过程
      InvocationHandler invocationhandler= new InvocationHandler(){
         public Object invoke(Object proxy,Method method,Object[] args)  throws Throwable
         {
//代理对象、需要重写的方法,方法里面的参数
            System.out.println("动态代理日志1");
            Object  result=method.invoke(target,args);
             System.out.println("动态代理日志2");
             return result;
         }
       };
  return Proxy.newProxyInstance(classloader,interfaces,invocationhandler);
   } 

 二、概念

面向切面编程,通过预编译和运行期间动态代理方式实现,在不改变原代码的情况下,给程序动态统一添加额外功能的一种技术。

  1. 横切关注点:各个模块解决同一个问题。如事务、日志都属于横切关注点
  2. 通知:想要增强的功能,比如事务、日志,所实现的方法叫通知方法
  3. 切面:封装通知方法的类。
  4. 目标:目标对象
  5. 代理:代理对象
  6. 连接点:spring允许你使用通知的位置
  7. 切入点:定位连接点的方式

三、注解实现AOP

 

 

切入点表达式:

JoinPoint获得切入点信息

 

切面的优先级用@Order实现

四、xml实现AOP

<aop:config>

  <aop:aspect  ref="logAspect">

    <aop:pointcut  id="pointcut"  expression="execution(* com.*((..))"/>

    <aop:before  method:"beforemethod"  pointcut-ref="pointcut"></aop:before>

  </aop:aspect>

</aop:config> 


网站公告

今日签到

点亮在社区的每一天
去签到