Spring 学习 day2 : Spring注解和代理模式

本文详细介绍了Spring框架中的IOC注解,包括XML与注解的区别、注解注入的步骤以及不同注解的用法。同时,文章还探讨了代理模式的概念,包括静态代理和动态代理的特点。

1.IOC注解

Spring框架中有注解和XML两种配置方式,这两种方式各有千秋

1.1 xml和注解两种注解方式的区别

1.1.1 XML配置

优点有:

1.XML配置方式进一步降低了耦合,使得应用更加容易扩展,即使对配置文件进一步修改也不需要工程进行修改和重新编译

2.在处理大的业务量的时候,用XML配置应该更好一些,因为XML更加清晰的表明了各个对象之间的关系,各个业务类之间的调用,同时Spring的相关配置也能一目了然.

缺点有:

配置文件读取和解析需要花费一定的时间,配置文件过多的时候难以管理,无法对配置的正确性进行校验,增加了测试的难度

1.1.2annotation配置

优点有:

1.在class文件中,可以降低维护成本,annotation的配置机制很明显简单

2.不需要第三方的解析工具,利用java反射技术就可以完成任务

3.编译是即可验证正确性,差错很及时

4.提高开发效率

缺点有:

1.如果需要对于annotation进行修改,那么要重新编译整个工程

2.业务类之间的关系不如XML配置那样清晰明了

3.如果在程序中的annotation比较多,直接影响代码质量,对于代码的简洁度有一定影响

XML方式在上一篇文章中已经详细记载,下面是注解方式

1.2 注解注入使用步骤

1.2.1 Autowired

1.创建项目并导入相关包 

https://note.youdao.com/yws/public/resource/98d524355f91bce5ac21605bcf29f24f/xmlnote/4489291AB17E472682C2F518E7349F18/16341

 2.开启注解的支持

<?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
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
	<!-- 引入注解约束 -->
	<!-- 使用注解形式自动装配 -->
	<context:annotation-config />
</beans>

3.业务类

业务类内容不变

public class UserService {
    private IUserDao userDao;

    @Autowired
    public void setUserDao(IUserDao userDao) {
        this.userDao = userDao;
    }
}

4.相关知识

@Autowired(自动封装)

用来将一个对象注入到当前类中

该注解可以加载set方法上或者直接加在属性上,如果写在setter方法上面,那就会通过setter方法进行注入,如果此时将setter方法干掉,那么就会报错.如果写在属性上面,比如说上面的IuserDao userDao上,那么此时是通过反射机制进行的注入,此时setter方法就算不存在也不会报错

注入时,会从spring容器(就是那个applicationContext.xml文件)中,找到一个和这个变量数据类型一致的实例化对象注入到当前类中,默认使用的byType,也就是根据数据类型匹配的

如果只能找到一个和该数据类型匹配的对象,那么就直接将该对象注入进来

如果容器中有多个匹配的数据类型对象,那么就会按照set方法对应的参数列表的局部变量名称来进行匹配

@Autowired(required=false) 
就说明 这个值可以为null,如果Spring容器中没有对应的对象,不会报错
默认为true,比如applicationContext.xml中没有创建dao对象,就会报错,加上required=false就不会报错

@Qualifier

以指定名字进行匹配,用在@Autowired放在setter方法上面时

private IUserDao userDao;
@Autowired
public void setUserDao(@Qualifier(“userDao2”)IUserDao userDao){};
这时候就不会按照userDao来进行匹配了,而是强制使用userDao2来进行比配,也就不会按照类型匹配了

1.2.2 Resource

用来将一个对象注入到当前类中

Resource这个注解是javaEE中的,放在javax包下,所以不需要导入其他的jar包即可使用

@Resource默认使用byName的方式,按照名字匹配,可以写在setter方法上也可以写在变量上

先匹配set方法后面的名字,没有的话就匹配set方法后面参数列表的名字

如果都没有就会转换为byType方式,根据类型匹配

当然我们也可以指定名字

@Resource(name=”userDao”)  

就相当于 Autowired和Qualifier 一起使用

1.业务类

@Resource(name="userDao")
  public void setUserDao(UserDao userDao) {
  	System.out.println("--------------");
  	this.userDao2 = userDao;
 }

2.测试类

@Test
public void testAdd() {
  ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(
    "applicationContext.xml");
   UserService userService = (UserService) applicationContext
   .getBean("userService");
   System.out.println(userService.getUserDao());
 }

1.3 注解实例化使用步骤

上面的两个注解是用来进行注入对象的,实例化对象也有对应的注解,先来个简单示例进行了解

1.3.1 配置文件

创建项目和导包,然后创建业务类,然后在配置文件中写上

<?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
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
	<!-- 使用注解形式自动装配 -->
	<context:annotation-config />
	<!-- 使用注解形式实例化对象 -->
	<context:component-scan base-package="com.tledu" />
</beans>

1.3.2 业务类

@Component  是业务类的注解方式

所有需要实例化对象(此处指借助spring在配置文件中用bean标签来创建实例的情况)的类上面都加上@Component  

默认是以类名首字母小写作为名字进行存储

可以使用@Component(“xxx”) 或者@Component(value=”xxx”)来设置名字

以上这三种写法都可以

@Component(value="userDao")
public class UserDaoImpl implements UserDao {
@Component
public class User {
@Component("userService")
public class UserService {

1.3.3 注解分类

像上面我们写的代码中,所有实例化对象都是要的是@Component 这样不是很好,官方给出了几个分类

@Controller :WEB 层 ,就是和页面交互的类

@Service :业务层 ,主要处理逻辑

@Repository :持久层 ,就是Dao操作数据库

这三个注解是为了让标注类本身的用途清晰,Spring 在后续版本会对其增强  

@Component: 最普通的组件,可以被注入到spring容器进行管理

@Value :用于注入普通类型. 可以写在变量上和setter方法上

@Autowired :自动装配,上面描述比较详细,可以参照上面

@Qualifier:强制使用名称注入.  

@Resource 相当于: @Autowired 和@Qualifier 一起使用

@Scope: 设置对象在spring容器中的生命周期

取值 :  

singleton:单例  

prototype:多例

@PostConstruct :相当于 init-method  

@PreDestroy :相当于 destroy-method  

1.3.4 注解区别

引用spring的官方文档中的一段描述:

在Spring2.0之前的版本中,@Repository注解可以标记在任何的类上,用来表明该类是用来执行与数据库相关的操作(即dao对象),并支持自动处理数据库操作产生的异常

在Spring2.5版本中,引入了更多的Spring类注解:@Component,@Service,@Controller。@Component是一个通用的Spring容器管理的单例bean组件。而@Repository, @Service, @Controller就是针对不同的使用场景所采取的特定功能化的注解组件。

因此,当你的一个类被@Component所注解,那么就意味着同样可以用@Repository, @Service, @Controller来替代它,同时这些注解会具备有更多的功能,而且功能各异。

最后,如果你不知道要在项目的业务层采用@Service还是@Component注解。那么,@Service是一个更好的选择。

就如上文所说的,@Repository早已被支持了在你的持久层作为一个标记可以去自动处理数据库操作产生的异常(译 者注:因为原生的java操作数据库所产生的异常只定义了几种,但是产生数据库异常的原因却有很多种,这样对于数据库操作的报错排查造成了一定的影响;而 Spring拓展了原生的持久层异常,针对不同的产生原因有了更多的异常进行描述。所以,在注解了@Repository的类上如果数据库操作中抛出了异常,就能对其进行处理,转而抛出的是翻译后的spring专属数据库异常,方便我们对异常进行排查处理)。

注解 含义

@Component 最普通的组件,可以被注入到spring容器进行管理

@Repository 作用于持久层

@Service 作用于业务逻辑层

@Controller 作用于表现层(spring-mvc的注解)

1.4 新注解

1.4.1 Configuratiion

作用:用来指定当前类是Spring的一个配置类,当创建容器时会从该类上加载注解

package com.tledu.config;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfiguration {
 
}

1.4.2 ComponentScan

作用:用于指定Spring在初始化容器时要扫描的包

作用和在 spring 的 xml 配置文件中的自动扫描是一样的。

属性: basePackages:用于指定要扫描的包。和该注解中的 value 属性作用一样。

@Configuration
@ComponentScan("com.tledu")
public class SpringConfiguration {
 
}

1.4.3 Bean

作用:该注解只能写在方法上,表明使用此方法创建一个对象,并且放入Spring容器

我们通过这个可以将数据源和JDBCTemplate对象导入到配置类中

package com.tledu.zrz.config;
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.context.annotation.Bean;
public class JdbcConfig {
/**
 * 创建一个数据源,并存入 spring 容器中
 * @return
 */
     @Bean(name = "dataSource")
    public BasicDataSource createDataSource() {
    try {
        BasicDataSource bds = new BasicDataSource();
        bds.setDriverClassName("com.mysql.jdbc.Driver");
        bds.setUrl("jdbc:mysql://localhost:3306/ssm");
        bds.setUsername("root");
        bds.setPassword("root");
        return bds;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
}

1.4.4 PropertySource

作用: 用于加载.properties 文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到properties 配置文件中,就可以使用此注解指定 properties 配置文件的位置。我们通过这个注解来将jdbc.properties文件加载到配置类中

属性: value[]:用于指定 properties 文件位置。如果是在类路径下,需要写上 classpath

package com.tledu.config;
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
public class JdbcConfig {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
/**
 * 创建一个数据源,并存入 spring 容器中
 *
 * @return
 */
@Bean(name = "dataSource")
public BasicDataSource createDataSource() {
    try {
        BasicDataSource bds = new BasicDataSource();
        bds.setDriverClassName(driver);
        bds.setUrl(url);
        bds.setUsername(username);
        bds.setPassword(password);
        return bds;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
}

1.4.5 Import

作用:用于导入其他的配置类,在引入其他配置类时,可以不再写@Configuration注解,当然,写上也没问题,我们用来创建几个配置类之间的关系

属性: value[]:用于指定其他配置类的字节码。

@Configuration
@ComponentScan("com.tledu.spring")
@Import({ JdbcConfig.class})
public class SpringConfiguration {
 
 
@Configuration
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig {

2.代理模式

           抽象   接口来表示
           真实   接口的一个实现类
           代理   接口的一个实现类,但是有对象真实的引用,功能比真实要强大
       
           静态代理 

创建代理的接口只能实现一些功能,耦合度太强
           
           动态代理

根据情况可以实现多种功能,低耦合

   创建动态代理类
              public class DynamicProxy implements InvocationHandler{
              
                    private Obejct obj;
              
                    public DynamicProxy(Obejct obj){
                      this.obj = obj
                    }
                    
                    public void after(){}
                    public void before(){}
                    
                    public Object invoke(Obejct obj,Method method,Object[] args){
                         before();
                         method.invoke(obj,args);
                         after();
                    }
              }
              

              测试:
              
              AbstractActor
              
              SomeOne obj = new SomeOne("张三");

                
              第一个参数是被代理类的类加载器,第二个参数是被代理类的接口,第三个是代理类对象
              AbstractActor actor = (AbstractActor)Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),new DynamicProxy(obj));
              
              actor.findHouse();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值