spring学习笔记2

复习

1 spring介绍

  • spring是一个轻量级J2EE开发框架,用来管理bean的一个容器.由单元测试,核心容器,AOP,DAO,ORM,JDBC,TX,Web,MVC等部分组成,
  • 我们主要学习使用两个核心内容: IOC,AOP

2 ioc是什么

  • IOC控制反转,是指将创建对象的控制权反转给spring容器
  • spring容器其实就是配置文件applicationContext.xml
  • 一个标签就会创建一个对象<bean id="" class="">

3 di是什么

  • DI依赖注入,属性赋值
  • set方法注入
    • 要赋值的属性,得有对应的set方法
    • 具体是在bean标签内部使用<property name="属性名" value="基本类型值" ref="引用类型,引用另一个对象的id">
  • 构造方法注入
  • 自动注入

4 自动注入是怎么注入的

  • 需要先在bean标签中设置自动注入的属性autowire
  • 指定自动注入的方式autowire=“byType|byName”
  • byType
    • 例如: UserServiceImpl中需要注入UserDao类型的属性
    • spring容器中有该UserDao类型的bean,就会注入
    • 但是!!!如果容器中有不止一个该UserDao类型的bean,就会注入失败!!
  • byName
    • 此时就可以使用byName来指定,注入哪个UserDao类型的bean
    • 容器中UserDao的id与UserServiceImpl类中UserDao属性名一致

bean的细节

IOC是可以控制创建对象时是: 单列还是多例

单例: 单实例,即单对象,也就是说这个类有且仅有一个对象

多例: 多实例,即多个对象,也就是说这个类可以有多个对象

<bean id="..." class="..." scope="singleton|prototype">
 
<!--
IOC,默认创建对象是单实例(scope="singleton"),即每次从容器中获得的是同一个对象
设置成scope="prototype",那就多实例,即每次从容器获得都是新对象
-->
<bean id="myClass" class="com.qf.model.MyClass" scope="prototype">
<property name="age" value="18"/>
<property name="name" value="京超啊"/>
</bean>
 @Test
    public void testIOC(){
        String path = "applicationContext.xml";
        // 通过配置文件,创建出容器
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(path);

        // 从容器获得对象
        MyClass myClass1 = context.getBean("myClass", MyClass.class);
        System.out.println(myClass1.hashCode());
		// 如果是单例,每次都是同一个地址
        MyClass myClass2 = context.getBean("myClass", MyClass.class);
        System.out.println(myClass2.hashCode());
		// 如果是多例,每次地址都不一样
        MyClass myClass3 = context.getBean("myClass", MyClass.class);
        System.out.println(myClass3.hashCode());
    }

3.注解开发
以前就可以还使用@WebServlet和@WebFilter注解,省去web.xml中写的配置
以后工作实际开发中,都会使用注解开发,效率很高!

IOC也要变成注解开发,用来省去在applicationContext.xml中的配置

注解解释
@Controller创建对象,用在控制层
@Service创建对象,用在业务层
@Repository创建对象,用在数据访问层
@Component创建对象,其他地方用
@Scope控制对象的单例|多例

以上注解可以取代配置文件中的<bean>标签

DI相关注解

注解解释
@Value给基本类型注入
@Autowired给引用类型自动注入(默认按照类型注入)byType
@Resource给引用类型自动注入(默认按照名字注入)byName
@Qualifier和@Autowired联用,可以实现按名字注入

以上注解可以取代配置文件中的<property>标签

@Service // 相对于是<bean id="" class="">标签,默认id是当前类名首字母小写
public class UserServiceImpl implements UserService {

    @Autowired  // 相对于是autowire=byType属性
    private UserDao userDao;

    public void findUserById() {
        System.out.println("UserServiceImpl--->业务层执行" );
        userDao.findUserById();
    }
}

开启注解扫秒

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

    <!-- 扫描注解,得让容器知道哪些类需要由Spring创建对象 -->
    <context:component-scan base-package="com.qf"/>

</beans>

测试

@Test
    public void testIOCandDIByAnno(){
        String path = "applicationContextByAnno.xml";
        // 通过配置文件,创建出容器
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(path);

        // 使用注解,默认id即对象名,是类名首字母小写
        UserService userService = context.getBean("userServiceImpl", UserService.class);
        userService.findUserById();
    }

注解使用细节

  1. IOC创建对象的注解,四个功能一样,都可以创建对象,只不过建议不同的位置使用不同的注解,见名知意

  2. 加上创建对象的注解后,默认对象名是类名首字母小写,即需要通过类名首字母小写从容器中获得对象

  3. 其实可以在注解中设置参数,给对象取名.例如@Service(“aaa”),以后就用aaa从容器中取值

  4. 自动注入时@Autowired ,默认按照类型注入

  5. 但是如果容器中有两个该类型的bean,自动注入就会失败,此时可以按名字注入

    @Resource(name="userDaoImpl2")
    
  6. 如果不使用@Resource按名字注入,也可以使用@Qualifier("userDaoImpl2")配合@Autowired一起实现,按照名字注入

  7. 可以给类加@Scope(“prototype|singleton”) 来控制单例多例

3 代理设计模式

代理的设计理念是限制对象的直接访问,即不能通过 new 的方式得到想要的对象,而是访问该对象的代理类。

这样的话,我们就保护了内部对象,如果有一天内部对象因为 某个原因换了个名或者换了个方法字段等等,那对访问者来说 一点不影响,因为他拿到的只是代理类而已,从而使该访问对 象具有高扩展性。

代理类可以实现拦截方法,修改原方法的参数和返回值,满足 了代理自身需求和目的,也就是代理的方法增强性。

按照代理的创建时期,代理可分为:静态代理动态代理

静态代理由开发者手动创建,在程序运行前,已经存在;

动态代理不需要手动创建,它是在程序运行时动态的创建代理类。


总结:代理模式–给某个目标对象提供一个代理,以改变对该对象的访问方式,以便于对目标方法的增强

3.1 静态代理

静态代理,在运行之前,提前先把代理创建好.

需求: 目标类(Fangdong),目标方法(chuzu()),来一个代理FangdongProxy(中介),中介会在目标方法执行前后,实现一些增强的功能.

目标接口和实现类

public interface Fangdong {
    void chuzu();
}

public class FangdongImpl implements Fangdong{
    public void chuzu() {
        System.out.println("房东出租房!" );
    }
}

代理

public class FangdongProxy {

    private Fangdong fangdong;

    public FangdongProxy(Fangdong fangdong){
        this.fangdong = fangdong;
    }

    // 代理执行方法
    public void chuzu(){

        // 前: 功能增强
        System.out.println("租房前: 中介发布消息");
        // 目标方法:出租房
        fangdong.chuzu();
        // 后: 功能增强
        System.out.println("中介签合同/后期水电气的维修" );
    }
}

测试

public static void main(String[] args) {

    // 找代理
    FangdongProxy proxy = new FangdongProxy(new FangdongImpl( ));
    proxy.chuzu();
}
租房前: 中介发布消息
房东出租房!
中介签合同/后期水电气的维修

3.2 动态代理

动态代理: 在程序运行过程中,动态的为目标类产生代理类

实现动态代理有两种方案:

  • jdk动态代理(JDK自带)
    - jdk动态代理,只能代理接口,即目标类必须有接口
  • cglib动态代理(第三方技术,需要导入第三方jar包)
    • cglib动态代理,目标类可以是接口也可以是实现类

3.2.1 JDK动态代理

在java的java.lang.reflect.InvocationHandler包下有一个InvocationHandler接口,可以实现动态产生代理对象.

public class MyInvocationHandler implements InvocationHandler {

    private Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }
    /**
     * @param proxy   代理对象
     * @param method  目标方法
     * @param args    目标方法执行需要的参数
     * @return 目标方法执行后返回值
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        // 目标方法前:
        System.out.println("前期宣传" );


        // 目标方法执行
        Object ret = method.invoke(target,args);


        // 目标方法后:
        System.out.println("后期维护" );
        return ret;
    }
}

测试

public class TestJDKDynamic {

    public static void main(String[] args) {

        // 动态代理,只需要给定目标类,就会产生目标类的代理对象

        // Class clazz = FangdongImpl.class;
        // ClassLoader loader = clazz.getClassLoader( );
        // Class[] interfaces = clazz.getInterfaces( );
        // MyInvocationHandler handler = new MyInvocationHandler(new FangdongImpl( ));
        // /**
        //  * @param   loader 被代理的类(目标类)的类加载器
        //  * @param   interfaces 被代理的类(目标类)的实现的接口数组
        //  * @param   handler 刚才自己创建的MyInvocationHandler
        //  * @return 返回代理对象
        //  */
        // Fangdong proxy = (Fangdong) Proxy.newProxyInstance(loader, interfaces, handler);
        //
        // proxy.chuzu();


        Class clazz = CarFactoryImpl.class;
        ClassLoader loader = clazz.getClassLoader( );
        Class[] interfaces = clazz.getInterfaces( );
        MyInvocationHandler handler = new MyInvocationHandler(new CarFactoryImpl( ));
        /**
         * @param   loader 被代理的类(目标类)的类加载器
         * @param   interfaces 被代理的类(目标类)的实现的接口数组
         * @param   handler 刚才自己创建的MyInvocationHandler
         * @return 返回代理对象
         */
        CarFactory proxy = (CarFactory) Proxy.newProxyInstance(loader, interfaces, handler);

        proxy.sellCar();

        //  JDK的动态代理,目标类必须实现接口,否则代理失败
    }
}

3.2.2 CGLIB动态代理

CGLIB是第三方技术,需要导入第三方jar包

但是Spring框架已经整合了CGLIB技术,即在导入spring依赖时,已经导入了cglib包了

public class MyProxyInterceptor implements MethodInterceptor {

    // cglib增强器
    private Enhancer enhancer = new Enhancer();

    public MyProxyInterceptor(Class targetClass){
        enhancer.setSuperclass(targetClass);
        enhancer.setCallback(this);
    }

    // 获得代理对象
    public Object getProxyBean() {
        return enhancer.create();
    }


    /**
     * @param target  目标对象(被代理对象)
     * @param method  目标方法
     * @param args  目标方法的参数
     * @param methodProxy 代理目标方法
     * @return 目标方法执行后,返回数据
     * @throws Throwable
     */
    public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

        // 前:
        System.out.println("前期宣传" );

        // 目标方法
        Object ret = methodProxy.invokeSuper(target, args);

        // 后:
        System.out.println("后期维护" );

        return ret;
    }
}

测试

public class TestCGLIB {

    public static void main(String[] args) {

        // 动态代理,只需要给定目标类,就会产生目标类的代理对象

        // MyProxyInterceptor myProxyInterceptor = new MyProxyInterceptor(FangdongImpl.class);
        // Fangdong proxy = (Fangdong) myProxyInterceptor.getProxyBean( );
        // proxy.chuzu();

        MyProxyInterceptor myProxyInterceptor = new MyProxyInterceptor(CarFactoryImpl.class);
        CarFactoryImpl proxy = (CarFactoryImpl) myProxyInterceptor.getProxyBean( );
        proxy.sellCar();

        // CGLIB代理的好处,就在于目标类即可以实现接口,也可以不用实现接口,都可以代理

    }
}

下一节springAOP
问:spring代理和通知的关系
答:aop的底层原理就是动态代理(JDK,CGLIB)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring是一个开源的Java框架,用于构建企业级应用程序。它提供了一种轻量级的、非侵入式的开发方式,通过依赖注入和面向切面编程等特性,简化了Java应用程序的开发过程。 以下是关于Spring学习的一些笔记: 1. IoC(控制反转):Spring通过IoC容器管理对象的创建和依赖关系的注入。通过配置文件或注解,将对象的创建和依赖关系的维护交给Spring容器来管理,降低了组件之间的耦合度。 2. DI(依赖注入):Spring通过依赖注入将对象之间的依赖关系解耦。通过构造函数、Setter方法或注解,将依赖的对象注入到目标对象中,使得对象之间的关系更加灵活和可维护。 3. AOP(面向切面编程):Spring提供了AOP的支持,可以将与业务逻辑无关的横切关注点(如日志、事务管理等)从业务逻辑中分离出来,提高了代码的可重用性和可维护性。 4. MVC(模型-视图-控制器):Spring提供了一个MVC框架,用于构建Web应用程序。通过DispatcherServlet、Controller、ViewResolver等组件,实现了请求的分发和处理,将业务逻辑和视图展示进行了分离。 5. JDBC和ORM支持:Spring提供了对JDBC和ORM框架(如Hibernate、MyBatis)的集成支持,简化了数据库访问的操作,提高了开发效率。 6. 事务管理:Spring提供了对事务的支持,通过声明式事务管理和编程式事务管理,实现了对数据库事务的控制和管理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

想要入门的程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值