初识Spring的注解配置

(一)导入配置Spring的jar包

创建一个maven项目,在pom.xml中配置spring 需要的jar包

		<?xml version="1.0" encoding="UTF-8"?>
		<project xmlns="http://maven.apache.org/POM/4.0.0"
		         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
		    <modelVersion>4.0.0</modelVersion>
		
		    <groupId>cn.lzj.</groupId>
		    <artifactId>Spring</artifactId>
		    <version>1.0-SNAPSHOT</version>
<!-- 
		配置spring的需要的jar包
-->
		    <dependencies>
		        <!-- 配置spring的核心包 -->
		        <dependency>
		            <groupId>org.springframework</groupId>
		            <artifactId>spring-core</artifactId>
		            <version>4.2.5.RELEASE</version>
		        </dependency>
		
		        <!-- 配置spring的上下文支持包 -->
		        <dependency>
		            <groupId>org.springframework</groupId>
		            <artifactId>spring-context</artifactId>
		            <version>4.2.5.RELEASE</version>
		        </dependency>
		
		        <!-- 配置AOP包 -->
		        <dependency>
		            <groupId>org.springframework</groupId>
		            <artifactId>spring-aop</artifactId>
		            <version>4.2.5.RELEASE</version>
		        </dependency>
		
		        <!--  配合spring的测试包 -->
		        <dependency>
		            <groupId>org.springframework</groupId>
		            <artifactId>spring-test</artifactId>
		            <version>4.2.5.RELEASE</version>
		        </dependency>
		
		        <!-- 配置切面包 -->
		        <dependency>
		            <groupId>org.aspectj</groupId>
		            <artifactId>aspectjweaver</artifactId>
		            <version>1.8.8</version>
		        </dependency>

<!-- 
		需要去读到java中的xml文件(默认不会编译)
-->
		        <!--  配置Juit测试包 -->
		        <dependency>
		            <groupId>junit</groupId>
		            <artifactId>junit</artifactId>
		            <version>4.12</version>
		        </dependency>
		
		    </dependencies>
		
		    <build>
		        <resources>
		            <resource>
		                <directory>src/main/java</directory>
		                <includes>
		                    <include>**/*.xml</include>
		                </includes>
		            </resource>
		            <resource>
		                <directory>src/test/java</directory>
		                <includes>
		                    <include>**/*.xml</include>
		                </includes>
		            </resource>
		        </resources>
		        <!-- 配置JDK1.8 -->
		        <plugins>
		            <plugin>
		                <groupId>org.apache.maven.plugins</groupId>
		                <artifactId>maven-compiler-plugin</artifactId>
		                <version>3.1</version>
		                <configuration>
		                    <source>1.8</source>
		                    <target>1.8</target>
		                </configuration>
		            </plugin>
		        </plugins>
		    </build>
		</project>

因为使用的是maven自动管理项目,所以在配置xml文件之后,idea可以自动导入jar包

(二) Spring构造器注入

(1) Spring的测试类准备

Spring测试复习:

在这里插入图片描述
1. 注入Spring测试的
2. 配置上下文的路径注解
三种方式:
1) 配置文件在classpath路径下
@ContextConfiguration(“classpath:SpringTest-Context.xml”)
2)配置文件在测试类的路径下
@ContextConfiguration(“classpath:cn/lzj/_01_contructor/SpringTest-Context.xml”)
3)配置文件的名为:测试类名-Context.xml
@ContextConfiguration

(2) Spring的注入构造器

标签: constructor-arg
属性: index/name/type = 下标/名称/类型
属性: value/ref = 普通的值/引用

1)根据下标index注入
<bean id="myBean" class="cn.lzj.constructor.MyBean">
   <constructor-arg index="0" value="木兰" />
   <constructor-arg index="1" value="18" />
</bean>
2)根据名称name注入
<bean id="myBean" class="cn.lzj.constructor.MyBean">
    <constructor-arg name="name" value="木兰" />
    <constructor-arg name="age" value="18" />
</bean>

3)根据类型type注入

使用全限定名,类型不能重复

<bean id="myBean" class="cn.lzj.constructor.MyBean">
    <constructor-arg type="java.lang.String" value="木兰" />
    <constructor-arg type="java.lang.Integer" value="18" />
</bean>
4)自动注入

spring会根据参数的顺序 和值得顺序,自动进行匹配(注意位置要一一对应)

<bean id="myBean" class="cn.lzj.constructor.MyBean">
    <constructor-arg value="木兰" />
    <constructor-arg value="18" />
</bean>
5)注入内部bean和外部bean

外部bean可以重复使用

	<!-- cn.lzj._01_contructor.MyBean  默认找的是类中的无参构造器 -->
    <bean id="myBean" class="cn.lzj._01_contructor.MyBean" >
        <!--  利于类中无参构造器,进行设置值 -->
        <constructor-arg index="0" value="木兰" />
        <constructor-arg index="1" value="15" />
        <!--  构造器中有自定义类的参数值 -->
        <!--  方法1  配置内部bean -->
        <constructor-arg>
            <bean class="cn.lzj._01_contructor.HisBean" />
        </constructor-arg>
        <!--  方法2  引入外部bean-->
        <constructor-arg ref="youBean" />
    </bean>
    <bean id="youBean" class="cn.lzj._01_contructor.YouBean" />

(三) Spring属性注入

(1) 准备一个MyBean

存放普通属性和集合、数组与properties

public class MyBean {
    // 普通属性
    private Long id;
    private String name;
    private Boolean sex;
    private BigDecimal salary;

    // 对象属性
    private List<String> list;
    private Set<String> set;
    private List<OtherBean> otherBeanList;
    private Set<OtherBean> otherBeanSet;

    //数组与properties
    private String[] arrays;
    private Properties props1; //Properties:特殊的Map(内部为key-value,要求只能是字符串)
    private Properties props2;
	
	getter 、setter 、toString 方法..........

(2) 普通属性注入

配置代码

	<!--普通属性 : 配置并设置值-->
        <property name="id" value="1" />
        <property name="name" value="丁香" />
        <property name="sex" value="true" />
        <property name="salary" value="123" />

(3) 集合属性注入

  • list(可以重复)与set(不允许重复)
  • 关键的那个标签(list,set,array),写错也可以用(但不建议)
  • 集合内也可以装其他类,然后注入内部bean

配置代码

		<!--  list; 有序,可重复-->
        <property name="list">
            <list>
                <value>梅</value>
                <value>兰</value>
                <value>竹</value>
                <value>竹</value>
            </list>
        </property>
        <!-- set; 无序,不可重复-->
        <property name="set">
            <set>
                <value>梅</value>
                <value>兰</value>
                <value>竹</value>
                <value>竹</value>
            </set>
        </property>

打印效果:

list:[梅, 兰, 竹, 竹]
set:[梅, 兰, 竹]

(4) 数组与properties

  • 数组标准写法:
		<!--String[] arrays:标准写法-->
        <property name="arrays">
            <array>
                <value>朱雀</value>
                <value>玄武</value>
            </array>
        </property>
  • 数组简写
    value中的字符串使用",“隔开,所以要求存放的字符串不能有”,"
		<!--String[] arrays:简写写法-->
        <property name="arrays" value="青龙,白虎" />
  • property标准写法(可以支持中文字符)
<!--Properties props1:标准写法(支持中文)-->
        <property name="props1">
            <props>
                <prop key="driver">com.mysql.jdbc.Driver</prop>
                <prop key="url">jdbc:mysql:///test</prop>
                <prop key="username">root中国人</prop>
            </props>
        </property>
  • property简写
<!--Properties props2:简写形式(不支持中文)-->
		<property name="props2">
            <value>
                driver=com.mysql.jdbc.Driver <!--  可以使用"=" ,也可以使用隔开 -->
                url=jdbc:mysql:///test
                username=root中国人
            </value>
        </property>

(四) Spring全注解注入

(1) 准备三层结构

在这里插入图片描述

(2) 配置上下文扫描,并扫描相应的包

  • 1.引入context的头
<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">
  • 2.启动包扫描机制

使用全注解,需要扫描包下对应类的注解
@Controller : WEB层
@Service : 业务层
@Repository : 持久层
@Component :组件(不知道哪一层,比如util需要让spring进行管理)
@Autowired :注入功能

	    <context:component-scan base-package="cn.lzj._03_allAnnotations" />
  • 3.将dao层注入到service层、service层注入到controller层
@Service
public class UserServiceImpl implements IUserService {
    @Autowired
    private IUserDao userDao;
----------------------------------------------------------------
@Controller
public class UserControllerImpl implements IUserController {
    @Autowired
    private IUserService userService;

(3) 处理多个bean类型

  • 注解的bean有默认名称(类名【首字母小写】) 如 userDaoImpl
  • 修改bean的名称 Component/Service/Repository/Controller(“名称”)
  • 在注入bean的时候加上一个限定注解

情景: 一个dao层的接口,有两个实现类

@Repository("userJdbcDao")
public class UserJdbcDaoImpl  implements IUserDao{
	public void save(){
		System.out.println("保存1....");
	}
}
-------------------------------------------------------
@Repository("userJpaDao")
public class UserJpaDaoImpl  implements IUserDao{
	public void save(){
		System.out.println("保存2....");
	}
}

调用名称的两个方案:
方案一:使用@Autowired

@Service
public class UserService {
	@Autowired
	@Qualifier("userJdbcDao")
	private IUserDao userDao;
	public void save(){
		userDao.save();
	}
}

方案二:使用@Resource

@Service
public class UserService {
	@Resource(name="userJpaDao")
	private IUserDao userDao;
	public void save(){
		userDao.save();
	}
}

(五) 静态代理模式

代理模式:类似于中介
静态代理模式,即装饰者模式
有三种角色:
① 抽象主题角色
② 真实主题角色
③ 代理主题角色

//通过JDK的方案创建一个动态代理对象呢?
/**
 * java.lang.reflect:Proxy(代理)对象
 * Foo Bar:张三,李四,王五
 *   ClassLoader loader :类加载器(随便给它一个)
     Class<?>[] interfaces:接口(为什么这里是一个数组)
     InvocationHandler h :增强功能(自己实现)
 */
IEmployeeService proxy = (IEmployeeService)Proxy.newProxyInstance(
    this.getClass().getClassLoader(),
    employeeService.getClass().getInterfaces(),
    new InvocationHandler() {
        /**
         * @param proxy :代理对象(没有用)
         * @param method :执行的方法
         * @param args :方法中的参数
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object result = null;
            try {
                txManager.begin();
                //在这里面完成功能增强
                //通过反射执行相应的方法
                result = method.invoke(employeeService, args);
                txManager.commit();
            } catch (Exception e) {
                txManager.rollback();
                e.printStackTrace();
            } finally {
                txManager.close();
            }
            return result;
        }
    });

(六)Spring的AOP

Spring的动态代理

  • ①JDK原始动态代理支持(性能好,要求被代理的类必须有实现接口)
  • ②CGLIB动态代理支持

(1) 通过XML配置

  • 在Spring的xml中导入AOP支持包
		<!-- 配置AOP包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.2.5.RELEASE</version>
        </dependency>
  • 准备接口:IEmployeeService(真实主题角色)
public interface IEmployeeService {
    void save();
    void update();
    void delete();
}
  • 准备实现 EmployeeServiceImpl(代理主题角色)
public class EmployeeServiceImpl implements IEmployeeService {
    @Override
    public void save() {
        System.out.println("送花给你....");
    }

    @Override
    public void update() {
        System.out.println("EmployeeServiceImpl udpate..");
    }

    @Override
    public void delete() {
        System.out.println("EmployeeServiceImpl delete..");
        //int i = 1/0;
    }
}
  • 模拟事务管理器
public class TxManager {

    public void begin(){
        System.out.println("开启事务...");
    }

    public void commit(){
        System.out.println("提交事务...");
    }

    public void rollback(Throwable e){
        System.out.println("回滚事务...,错误的原因:"+e.getMessage());
    }

    public void close(){
        System.out.println("关闭资源...");
    }

    //搞了一个ProceedingJoinPoint(连接点对象)
    public void around(ProceedingJoinPoint joinPoint){
        System.out.println(joinPoint.getArgs()); //参数
        System.out.println(joinPoint.getSignature()); //方法签名(这个方法的所有信息)
        System.out.println(joinPoint.getTarget().getClass()); //真实主题角色
        System.out.println(joinPoint.getThis().getClass()); //代理主题角色
        try {
            begin();
            joinPoint.proceed(); //执行对应的方法
            commit();
        } catch (Throwable e) {
            rollback(e);
            e.printStackTrace();
        } finally {
            close();
        }
    }

}
  • 配置
    引入aop的头
    准备两个bean(EmployeeServiceImpl,TxManager)
    如果有环绕通知,其它通知就不需要了
    注意:何时,何地,做什么
<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
">

    <!--真实主题角色-->
    <bean id="employeeService" class="cn.itsource._08_xmlaop.EmployeeServiceImpl" />

    <!--准备一个事务-->
    <bean id="txManager" class="cn.itsource._08_xmlaop.TxManager" />

    <!--何时,何地,做什么事-->
    <!--代表要做一个AOP的配置-->
    <aop:config>
        <!--
            配置(定义)切点 在哪些类的哪些方法进行功能
                id:切点名称(随便取)
                expression:表达式(最后定位都是方法)
                    *:所有返回值
                    cn.itsource._08_xmlaop:对应的包
                    I*Service:以I开头,Service结尾的所有接口(所有实现接口的方法)
                    *:所有方法
                    (..):所有参数
          -->
        <aop:pointcut id="pointcut" expression="execution(* cn.lzj._08_xmlaop.I*Service.*(..))" />
        <!--
            切面:由切点和增强组成
                ref="txManager" -> 对应的增强类
        -->
        <aop:aspect ref="txManager">
            <!--
            aop:before:前置通知
                何地:在哪些类的哪些方法中:pointcut
                何时:在方法执行之前:before
                做什么事:执行txManager这个bean中的begin方法
                 try {
                        //前置通知
                        result = method.invoke(employeeService, args);
                        //后置通知
                    } catch (Exception e) {
                        //异常通知
                    } finally {
                        //最终通知
                    }
            -->
            <!--<aop:before method="begin" pointcut-ref="pointcut" />-->
            <!--后置通知-->
            <!--<aop:after-returning method="commit" pointcut-ref="pointcut"  />-->
            <!--异常通知 throwing这个错,方法中才可以获到(名字必需一致) -->
            <!--<aop:after-throwing method="rollback" pointcut-ref="pointcut" throwing="e" />-->
            <!--最终通知 -->
            <!--<aop:after method="close" pointcut-ref="pointcut"  />-->
            <!--环绕通知-->
            <aop:around method="around" pointcut-ref="pointcut"  />
        </aop:aspect>
    </aop:config>
</beans>

  • 测试

    查看一下这个对象是否已经被代理
    声明必需是接口
    测试一下有异常与没有异常的区别

(2) 注解版

需要在相应的bean上加注解
配置包的扫描
所有的配置都是在TxManager加注解
  • xml配置
<?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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
">
    <!--扫描包-->
    <context:component-scan base-package="cn.itsource._09_annoaop" />
    <!--支持切面的注解-->
    <aop:aspectj-autoproxy />
</beans>

  • TxManager

    切点的名字是 方法名()

package cn.lzj._09_annoaop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @Aspect -> <aop:aspect ref="txManager">
 */
@Component
@Aspect
public class TxManager {
    /**
     * 切点:
     * <aop:pointcut id="pointcut()" expression="execution(* cn.itsource._09_annoaop.I*Service.*(..))" />
     */
    @Pointcut("execution(* cn.lzj._09_annoaop.I*Service.*(..))")
    public void pointcut(){}

//    @Before("pointcut()")
    public void begin(){
        System.out.println("开启事务...");
    }

//    @AfterReturning("pointcut()")
    public void commit(){
        System.out.println("提交事务...");
    }

//    @AfterThrowing(pointcut = "pointcut()",throwing = "e")
    public void rollback(Throwable e){
        System.out.println("回滚事务...,错误的原因:"+e.getMessage());
    }

//    @After("pointcut()")
    public void close(){
        System.out.println("关闭资源...");
    }

    //搞了一个ProceedingJoinPoint(连接点对象)
    @Around("pointcut()")
    public void around(ProceedingJoinPoint joinPoint){
        System.out.println(joinPoint.getArgs()); //参数
        System.out.println(joinPoint.getSignature()); //方法签名(这个方法的所有信息)
        System.out.println(joinPoint.getTarget().getClass()); //真实主题角色
        System.out.println(joinPoint.getThis().getClass()); //代理主题角色
        try {
            begin();
            joinPoint.proceed(); //执行对应的方法
            commit();
        } catch (Throwable e) {
            rollback(e);
            e.printStackTrace();
        } finally {
            close();
        }
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值