Spring笔记

spring

简介

轻量级的控制反转IOC和面向切面编程AOP的框架。

7大模块

spring AOP ,spring Core , spring WebMVC , spring Web , spring Context , spring ORM , spring DAO

扩展

spring boot
构建,快速开发微服务,约定大于配置
spring Cloud
spring Cloud Data Flow

IOC控制反转

在这里插入图片描述
先执行配置文件,applicationContext.xml实例化
实例化对象Person为变量名person,对person的name,age进行赋值,使用ref属性引用Spring容器中创建好的对象

	<bean id="person" class="com.example.chapter_dog.Person">
        <property name="name" value="林师傅"/>
        <property name="age" value="43"/>
        <property name="dog" ref="dog"/>
    </bean>
    <bean id="dog" class="com.example.chapter_dog.Dog">
        <property name="name" value="小黑"/>
        <property name="brand" value="贵宾"/>
    </bean>

在测试类使用ApplicationContext获取spring的上下文对象(拿到容器),spring代替你new对象
通过修改xml修改程序

	ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    Person person = (Person)ac.getBean("person");
    person.porting();
控制反转

依赖注入:利用set方法来注入,xml中使用set方法实例化
对象由spring创建,管理,装配

bean无参构造
配置文件加载时,容器就已经初始化对象

	<bean id="person1" class="com.example.chapter_dog.Person">

    </bean>

bean有参构造
了解:别名

<!--name:别名-->
	<bean id="person1" class="com.example.chapter_dog.Person" name="aaaa">
        <constructor-arg index="0" value="wangshifu"/>
        <constructor-arg index="1" value="20"/>
    </bean>
    或者
    <bean id="person1" class="com.example.chapter_dog.Person">
        <constructor-arg name="name" value="wangshifu"/>
        <constructor-arg name="age" value="20"/>
    </bean>
    或者(不推荐)
    <bean id="person1" class="com.example.chapter_dog.Person">
        <constructor-arg type="java.lang.String" value="wangshifu"/>
        <constructor-arg type="java.lang.String" value="20"/>
    </bean>
import

使用import将所有人的xml合并为一个

	<import resource="beans.xml"/>
    <import resource="beans1.xml"/>

依赖注入

构造器注入

依赖:bean对象创建依赖容器
注入:bean所有属性由容器注入

set方式注入

	<property name="name" value="wang=rui"/>
        <property name="address" ref="address"/>
<!--数组-->
        <property name="books">
            <array>
                <value>水浒传</value>
                <value>三国</value>
                <value>西游记</value>
            </array>
        </property>
<!--列表-->
        <property name="hobbys">
            <list>
                <value>听歌</value>
                <value>玩游戏</value>
            </list>
        </property>
<!--        Map-->
        <property name="card">
            <map>
                <entry key="学号" value="123456789"/>
                <entry key="身份证" value="78916534864564165"/>
            </map>
        </property>
<!--        Set-->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>Pokemmo</value>
            </set>
        </property>
<!--        null-->
        <property name="wife">
            <null></null>
        </property>
        <property name="info">
            <props>
                <prop key="username">root</prop>
                <prop key="password">123456</prop>
            </props>
        </property>

拓展方式注入

p命名空间(set注入)和c命名空间(构造器注入constructor-arg)注入

导入xml约束
	xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"

	<bean id="stu1" class="com.example.spring_di_set.Student" p:name="wangrui"/>
    <bean id="stu2" class="com.example.spring_di_set.Student" c:name="wangrui"/>

bean作用域

singleton单例模式
spring默认的模式,bean的每次实例化共享一个对象

	<bean id="stu1" class="com.example.spring_di_set.Student" p:name="wangrui" scope="singleton"/>

prototype原型模式
每次从容器get,都会产生一个新对象

	<bean id="stu1" class="com.example.spring_di_set.Student" p:name="wangrui" scope="prototype"/>

bean自动装配

byName自动在容器上下文中查找,和自己对象set方法后面的值对应的beanid,保证id值唯一

	<bean id="stu3" class="com.example.spring_di_set.Student" autowire="byName"></bean>

byType自动在容器上下文中查找,和自己对象属性相同的beanid,保证所有bean的class唯一,保证属性类型一样

	<bean id="stu3" class="com.example.spring_di_set.Student" autowire="byType"></bean>
注解自动装配

注解使用反射实现

1.导入context约束

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:context="http://www.springframework.org/schema/context"
       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/context.xsd
">

2.@Autowired直接在属性上使用

public void Student{
	@Autowired
    private Address address;
}

开启注解的支持context:annotation-config

	<context:annotation-config></context:annotation-config>
    <bean id="stu" class="com.example.spring_di_set.Student"/>
    <bean id="address" class="com.example.spring_di_set.Address"/>

3.如果有多个bean对象,可以和@Qualifier配合使用,指定唯一bean对象,value值为bean对象id

public void Student{
	@Autowired
    @Qualifier(value = "address111")
}

4.@Resource注解
也是自动装配
@Autowired通过byType实现
@Resource默认通过byName实现,找不到则通过byType实现

5.扫描指定的包,使用@Component

	@Value("wang")//赋值
	private String name;
	配合@Component使用
	<context:component-scan base-package="com.qst.ch_111.dao"/>

6.@Component衍生注解

  • dao层常用@Repository
  • service层常用@Service
  • controller层常用@Controller
    祝贺四个功能一样,代表类注册到spring,装配bean

7.在类上添加注解@Scope(“singleton”)设置作用域

总结
  • 使用注解需要导入spring-aop.jar
  • 使用注解需要导入约束context
  • 使用注解维护困难
  • xml适用于任何场合

使用java配置Spring

@Configuration代表这是一个配置类,类似于applicationContext.xml
@bean:注册一个bean,相当于bean.xml中的一个,方法名=id,返回值=class

@Configuration
@ComponentScan("com.example.spring_di_set")//扫描包
public class WangConfig {
    @Bean
    public Student getStudent(){
        return new Student();
    }
}

测试配置类

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(WangConfig.class);
        User user = ac.getBean("getUser",User.class);
        System.out.println(user.toString());
    }
}

实体类,使用@Value赋值
在这里插入图片描述

如果扫描包可以不用@bean
java配置的两种方式:配置类+@bean 或者 配置类+扫描包

AOP

代理模式

静态代理

代理模式是springAOP的底层
分类:

  • 静态代理
  • 动态代理
    在这里插入图片描述

客户找中介租房子例子:
1.真实角色(房东)

public class Host implements Rent{
    @Override
    public void rent() {
        System.out.println("房东出租房子");
    }
}

2.代理角色(中介)

public class Proxy implements Rent{
    Host host = new Host();

    public Proxy() {
    }

    public Proxy(Host host) {
        this.host = host;
    }

    //房东出租房子
    @Override
    public void rent() {
        look();
        host.rent();

    }
    //看房子(代理功能扩展)
    public void look(){
        System.out.println("带客户看房");
    }
}

3.相同接口(租房行为)

public interface Rent {
    void rent();
}

4.客户(人)

public class People {
    public static void main(String[] args) {
        Host host =  new Host();
        Proxy proxy = new Proxy(host);
        proxy.rent();
    }
}

代理模式好处:
是真实角色操作更加纯粹,
公共操作交给代理,业务分工,
公共业务扩展是,方便集中管理
缺点:
一个真实角色产生一个代理角色,开发效率低

动态代理

动态代理底层是反射

反射Reflection

反射就是获取类的结构,即获取Class(不是class),可以在程序运行中改变某些条件

		//创建Class方式一
        Class c1 = person.getClass();
        //创建Class方式二
        Class c2 = Class.forName("com.example.reflection.Student");
        //创建Class方式三
        Class c3 = Student.class;

获取类运行时的结构(属性,方法,,,)

		//获得类的名字
        System.out.println(c1.getName());//包名+类名
        System.out.println(c1.getSimpleName());//类名
        //获得类的属性
        Field[] fields = c1.getFields();//获得类的public属性
        for (Field field : fields) {
            System.out.println("public属性"+field);
        }
        fields=c1.getDeclaredFields();//获得所有属性
        for (Field field : fields) {
            System.out.println("属性"+field);
        }
        //获得指定属性
        Field name = c1.getField("name");
        System.out.println(name);

        //获得类的方法
        Method[] methods = c1.getMethods();//获得本类及其父类的public方法
        for (Method method : methods) {
            System.out.println("public方法"+method);
        }
        methods=c1.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println("所有"+method);
        }
        //获得指定方法
        Method getName = c1.getMethod("getName", null);
        System.out.println(getName);
        Method setName = c1.getMethod("setName", String.class);
        System.out.println(setName);
        //获得构造器
        Constructor[] constructors = c1.getConstructors();//public
        for (Constructor constructor : constructors) {
            System.out.println(constructors);
        }
        constructors=c1.getDeclaredConstructors();//所有
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        //获得指定构造器
        Constructor declaredConstructor = c1.getConstructor(String.class);
        System.out.println(declaredConstructor);
类加载器ClassLoader

1、分类:

  • 启动(Bookstrap)类加载器,ClassLoader,
  • 扩展(Extension)类加载器,由ExtClassLoader实现
  • 系统(System)类加载器,由AppClassLoader实现
    2、双亲委派机制
    类加载器有任务委托父类,依次递归,到启动类加载器(根加载器)
    在这里插入图片描述
public class Test_ClassLoader {
    public static void main(String[] args) throws ClassNotFoundException {
        //类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);
        //扩展加载器
        ClassLoader parent = systemClassLoader.getParent();
        System.out.println(parent);
        //根加载器
        ClassLoader parent1 = parent.getParent();
        System.out.println(parent1);
        //测试当前类是谁加载的
        ClassLoader classLoader = Class.forName("com.example.reflection.Test_ClassLoader").getClassLoader();
        System.out.println(classLoader);
        //测试JDK内置类谁加载的
        ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader();
        System.out.println(classLoader1);
        //获得系统类加载器可以加载的路径
        System.out.println(System.getProperty("java.class.path"));
    }
}

输出结果

sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@1540e19d
null
sun.misc.Launcher$AppClassLoader@18b4aac2
null
动态代理

动态代理和静态代理角色一样
动态代理的代理类是动态生成得到,不是直接写好的
动态代理代理的是接口,getProxy返回值要转为代理的接口类型

分类:

  • 基于接口的动态代理,JDK代理
  • 基于类的动态代理,cglib代理
  • java字节码实现,javassist

动态代理例子:
使用动态生成代理类,只需传入不同接口就可切换要代理的接口,在Test切换接口的实现类就可切换代理的类。
调用处理程序

public class Proxy_InvocationHandler implements InvocationHandler {     //动态代理,InvocationHandler是代理处理程序
    //被代理的接口
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    //生成代理类,三个参数(获取类加载器,获取接口,InvocationHandler)
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }
    /**
     * proxy:代理类代理的真实代理对象com.sun.proxy.$Proxy0
     * method:我们所要调用某个对象真实的方法的Method对象
     * args:指代代理对象方法传递的参数
     */
    @Override
    //处理代理实例,并返回结果,在生成代理类时自动执行
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log(method.getName());      //method.getName:通过反射获取执行的方法的名字
        Object invoke = method.invoke(target, args);
        return invoke;
    }
    //代理类的扩展功能,日志功能
    public void log(String msg){
        System.out.println("执行了"+msg+"方法");
    }
}

newProxyInstance方法的三个参数:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

  • loader:一个classloader对象,定义了由哪个classloader对象对生成的代理类进行加载
  • interfaces:一个interface对象数组,表示我们将要给我们的代理对象提供一组什么样的接口,如果我们提供了这样一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法。
  • h:一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用。
    测试
public class Client {
    public static void main(String[] args) {
        Host host =new Host();      //接口的实现类(真实角色),可切换实现类来切换代理的对象
        //通过调用程序处理角色来处理要调用的接口
        Proxy_InvocationHandler pih = new Proxy_InvocationHandler();
        pih.setTarget(host);        //传入代理要代理的接口
        Rent proxy = (Rent) pih.getProxy();     //创建代理类,改变类型为接口类型
        proxy.rent();       //测试接口的方法
    }
}

动态代理好处:

  • 一个动态代理代理得到是一个接口,一般就是对应的一类业务
  • 一个动态代理可以代理多个类,只要他们实现了同一接口
AOP
aop实现方式一:使用Spring的API接口实现

可以在实现MethodBeforeAdvice的类中使用反射,获取类的结构

1.xml配置文件,导入aop约束,
在这里插入图片描述
2.log、afterlog是编写的类实现BeforeAdvice和AfterAdvice
log
在这里插入图片描述
afterlog
在这里插入图片描述
3.测试
在这里插入图片描述
4.结果
在这里插入图片描述

aop实现方式二:自定义实现AOP(切面定义)

before:前置通知、afterReturning:后置通知、around:环绕通知、afterThrowing:异常通知、after:最终通知

实体类

public class UserServiceImpl implements UserService{
    @Override
    public void add() {
        System.out.println("添加");
    }

    @Override
    public void delete() {
        System.out.println("删除");
    }
}

applicationContext.xml配置

    <bean id="log_1" class="com.example.spring_aop.log.Log_1"/>
    <bean id="userService" class="com.example.spring_aop.service.UserServiceImpl"/>
<!--    方式二:自定义-->
    <aop:config>
<!--        切面-->
        <aop:aspect id="aspect" ref="log_1">
<!--            切入点-->
            <aop:pointcut id="pointcut" expression="execution(* com.example.spring_aop.service.*.*(..))"/>
<!--            通知-->
            <aop:before method="myBefore" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>

自定义通知

public class Log_1 {
    public void myBefore(){
        System.out.println("===前置日志===");
    }

}

测试

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = ac.getBean("userService", UserService.class);
        userService.add();
    }
}

结果
在这里插入图片描述

aop实现方式三:使用注解实现AOP

实体类

public class UserServiceImpl implements UserService{
    @Override
    public void add() {
        System.out.println("添加");
    }

    @Override
    public void delete() {
        System.out.println("删除");
    }
}

xml配置

    <bean id="log" class="com.example.spring_aop.log.Log"/>
<!--    方式三:使用注解-->
<!--    proxy-target-class默认是false,代表jdk代理,true是cglib代理-->
    <aop:aspectj-autoproxy/>

通知

@Aspect
public class Log {
    @Pointcut("execution(* com.example.spring_aop.service.*.*(..))")
    private void pointcut(){};
    @Before("pointcut()")
    public void myBefore(){
        System.out.println("前置日志===");
    }

}

结果
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值