Spring(注解+依赖注入+无配置注解+AOP)适合回顾♥♥

Posted 牛牛最爱喝兽奶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring(注解+依赖注入+无配置注解+AOP)适合回顾♥♥相关的知识,希望对你有一定的参考价值。

Spring注解



bean 注入与装配的的方式有很多种,可以通过 xml,get set 方式,构造函数或者注解等。简单易
用的方式就是使用 Spring 的注解了,Spring 提供了大量的注解方式。

IOC和DI

在介绍注解之前呢,我先来给大家谈谈IOC(控制反转和依赖注入)。作为Spring核心思想之一的IOC,唯一目的就是降低对象与对象之间的一个耦合度,例如我们平时写的代码,经常将几个对象之间进行嵌套使用,错综复杂管理起来极不方便,所以导致了代码维护困难。如下图:
其实耦合关系不仅会出现在对象与对象之间,也会出现在软件系统的各模块之间,以及软件系统和硬件系统之间。要想降低对象与对象之间的一个耦合度,科学家们提出了IOC控制反转的思想,如下图:
通过IOC容器来过度对象与对象之间的连接关系,若此时去掉IOC容器四个对象就独立出来了。且相互之间毫无联系。控制反转,传统的应用程序中,控制权在程序本身,程序的控制流程完全由开发者控制,这种模式的缺点是,一个组件如果要使用另一个组件,必须先知道如何正确地创建它。在IoC模式下,控制权发生了反转,即从应用程序转移到了IoC容器,所有组件不再由应用程序自己创建和配置,而是由IoC容器负责,这样,应用程序只需要直接使用已经创建好并且配置好的组件。为了能让组件在IoC容器中被“装配”出来,需要某种“注入”机制(DI)。由原来的主动创建,到现在的被动实现,控制权实现了反转,也就叫控制反转。由主动行为变为了被动行为,控制权颠倒过来了,这就是“控制反转”这个名称的由来。
DI: 实际上DI就是IOC的另一个名字,区别不是很大,控制反转要依赖于DI注入,实际上给出了实现IOC的方法:注入。所谓依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。 所以,依赖注入(DI)和控制反转(IOC)是从不同的角度的描述的同一件事情,指就是通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦。
(注入的方式已在另一篇文章介绍DI注入方式

注解


注解
1.注解的使用
@Controller
@Controller(“Bean的名称”) 定义控制层Bean,如Action
@Service
@Service(“Bean的名称”) 定义业务层Bean
@Repository
@Repository(“Bean的名称”) 定义DAO层Bean
@Component 定义Bean, 不好归类时使用.
可以指定bean的id,默认时类名首字母小写。@Component注解就相当于定义了一个Bean

@Autowired  (Spring提供的)@Autowired就相当于把指定类型的Bean注入到指定的字段中。为了给类成员变量赋值。

默认按类型匹配,自动装配(Spring提供的),可以写在成员属性上,或写在setter方法上
@Autowired(required=true)  
一定要找到匹配的Bean,否则抛异常。 默认值就是true
@Autowired
@Qualifier("bean的名字") 
按名称装配Bean,与@Autowired组合使用,解决按类型匹配找到多个Bean问题。

@Resource   JSR-250提供的
默认按名称装配,当找不到名称匹配的bean再按类型装配.
可以写在成员属性上,或写在setter方法上
可以通过@Resource(name="beanName") 指定被注入的bean的名称, 要是未指定name属性, 默认使用成员属性的变量名,一般不用写name属性.
@Resource(name="beanName")指定了name属性,按名称注入但没找到bean, 就不会再按类型装配了.
@Inject   是JSR-330提供的
按类型装配,功能比@Autowired少,没有使用的必要。

bean配置文件中必须加入以下配置,否则注解不起作用。

<context:component-scan base-package="com.xiaoliu.pojo">
</context:component-scan>

dao层

import org.springframework.stereotype.Repository;
@Repository
public class DaoTest 
    public void add()
        System.out.println("Dao_test com on!");
    

服务层

@org.springframework.stereotype.Service//将该类交给spring来管理
public class Service 
    @Qualifier("daoTest")//指定加载daoTest
    @Autowired//根据变量类型赋值
    private DaoTest daoTest;
    public void add()
        daoTest.add();
        System.out.println("service_test hello");
    

控制层

@Controller
public class Action 
    @Autowired
    private Service service;
    public void add()
        service.add();
        System.out.println("Action come on!");
    

测试:

    @Test
    public void test3()
        ApplicationContext at = new ClassPathXmlApplicationContext("spring-action.xml");
        Action a = at.getBean("action",Action.class);//默认id是类名首字母小写
        System.out.println(a);
        Service s = at.getBean(Service.class);//("service",Service.class)
        System.out.println(s);
        DaoTest d = at.getBean(DaoTest.class);
        System.out.println(d);
        a.add();
    

本质上就是将类交给IOC容器进行管理
2.无配置注解

    <!--扫描包+注解-->
    <context:component-scan base-package="com.xiaoliu"></context:component-scan>
    <!--出去控制层注解,-->
    <context:component-scan base-package="com.xiaoliu.pojo" use-default-filters="false"><!--只包含必须取消默认-->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <context:component-scan base-package="com.xiaoliu.pojo" ><!--不包含-->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>

测试案例

1.引入外部文件以及数据库连接池的配置(druid.pool)

<!-- 导入外部文件-->
    <context:property-placeholder location="db.properties"></context:property-placeholder>
    <bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
        <property name="driverClassName" value="$jdbc.driverClassName"></property>
        <property name="url" value="$jdbc.url"></property>
        <property name="password" value="$jdbc.password"></property>
        <property name="username" value="$jdbc.name"></property>
    </bean>

IOC核心原理

IOC采用了设计模式之一的工厂模式,一个工厂可以生产出多个对象,但是首先创建出工厂对象,在生产出产品对象。静态工厂不需要工厂对象。
BeanFactory和ApplicationContext的区别在于,BeanFactory的实现是按需创建,即第一次获取Bean时才创建这个Bean,而ApplicationContext会一次性创建所有的Bean。实际上,ApplicationContext接口是从BeanFactory接口继承而来的,并且,ApplicationContext提供了一些额外的功能,包括国际化支持、事件和通知机制等。通常情况下,我们总是使用ApplicationContext,很少会考虑使用BeanFactory。


DI依赖注入
有时候创建的bean对象要依赖于其他的bean对象,此时就需要链接注入其他对象。例如:

    <bean name="pYn" class="com.xiaoliu.pojo.test.Person">
        <property name="Mycar">
            <bean class="com.xiaoliu.pojo.test.Car" p:brand="北汽" p:maxpeed="100" p:price="2000000"></bean>
        </property>
    </bean>

或者可以使用ref链接:

  <bean id="p" class="com.openlab.pojo.Person">
        <property name="name">
           <value>李思峰</value>
        </property>
        <property name="age">
          <value>399</value>
        </property>
        <property name="desk" ref="desk"></property>
        </bean>
        <bean id="desk" class="com.openlab.pojo.Desk">
          <property name="deskName" value="书桌5号"></property>
          <property name="deskSize" value="10"></property>
        </bean>

AOP的含义

正常程序流程

面向切面编程,它只是一种编程思想。在程序纵向的执行流程中,针对某一个方法,添加通知去形成切面的过程,我们把这个过程称为面向切面。

使用切面编程的好处,在不修改源码的基础下就可以实现功能的扩展,释放相应的业务逻辑,让方法更加明确。增强了程序的扩展性!采用横向抽取机制,取代了传统纵向继承体系重复性代码。
主要意图:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
底层实现方式
动态代理:我所理解的代理思想无非就是自己不能或不想直接去做某件事,而需要中间人来帮我完成部分工作。
1.JDK动态代理实现
动态代理是利用反射机制在运行时创建代理类,仅支持接口。
代码:
接口

public interface DeptDao 
    public  int upate();


实现类

public class DeptDaoImpl implements DeptDao

    @Override
    public int upate() 

        return 1234;

    

代理类

public class MyHandle implements InvocationHandler 
    private Object target;
    public MyHandle(Object target)//指定代理对象

        this.target = target;
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable //实现invoke方法,proxy代表代理对象,method表示需要增强的方法,args表示值的参数列表
        System.out.println("-------Methon:"+method+"---------args"+ Arrays.toString(args));
        System.out.println("事务开启之前-----------");

        Object res = method.invoke(target,args);//target DeptDao对象
        System.out.println(res);
        System.out.println("事务关闭之后-----------");
        return res;
    

测试类:

public class ProxyTest 
        synchronized
    public static void main(String[] args) 
        DeptDaoImpl dept = new DeptDaoImpl();
        Class[] classes = dept.getClass().getInterfaces();//获取接口class对象集合
        DeptDao dao = (DeptDao) Proxy.newProxyInstance(ProxyTest.class.getClassLoader(),classes,new MyHandle(dept));//类加载器,接口集合,指定代理类代理的目标对象

        int res = dao.upate();//代理对象的invok方法,并不会去执行Impl中的方法


    

结果

代理对象帮我们实现的upate方法!
2.cglib动态代理实现
针对类实现代理,对是否实现接口无要求。原理是对指定的类生成一个子类,覆盖其中的方法,因为是继承,所以被代理的类或方法最好不要声明为final类型。
1.定义一个实现了MethodInterceptor接口的类。
2.实现其intercept()方法,在其中调用proxy.invokeSuper( )。
**特点:**不需要实现接口,但是需要继承的子类基于字节码生成的真实对象的子类,运行效率高于jdk的动态代理

AOP操作术语:
Joinpoint(连接点): 类里面可以被增强的方法,这些方法称为连接点

原有功能:切点:pointcut所谓切入点是指我们要对哪些Joinpoint进行拦截的定义

Aspect(切面): 是切入点和通知(引介)的结合

前置通知:在切点之前加入的功能, before advice

后置通知:在切点之后加入的功能, after advice

异常通知:在切点执行过程中 如果发生异常,会触发异常通知 throw advice

以上所有的功能 被称为切面
织入: 把切面嵌入到原有的功能当中
环绕通知: 前置通知+后置通知

注解方式实现:
只需要添加将类交给spring管理然后让spring能够扫描到你的包,并且支持AOP。

<context:component-scan base-package="com.xiaoliu">
</context:component-scan>
    <aop:aspectj-autoproxy/>
@Component
@Aspect
@Order(0)
public class UserDaoProxy 
   @Pointcut(value = "execution(* com.xiaoliu.pojo.aop.*.*(..))")
   public void point()

   
   @Before(value="point()")
    public  void before()
        System.out.println("before");
    
    @After(value = "point()")
    public void after()
        System.out.println("after");
    
    @Around(value = "point()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable 
        System.out.println("aroundBefore");
        joinPoint.proceed();
        System.out.println("aroundAfter");
    
    @AfterReturning(value = "point()")
    public void afterreturn()
        System.out.println("afterreturn");
    
    @AfterThrowing(value = "point()")
    public void afterthrow()
       System.err.println("发生异常");

    

测试

    public void test01()
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config-03.xml");
        UserDao ud = context.getBean("userDao",UserDao.class);
        System.out.println(ud.update());
        ud.save();
    

测试结果:

第二种写aop配置文件

        <bean id="proxy" class="com.xiaoliu.pojo.aop.UserDaoProxy"></bean>
        <aop:config>
                <aop:aspect id="aspect" ref="proxy">
                <aop:pointcut id="point" expression="execution(* com.xiaoliu.pojo.aop.*.*(..))"/>
                        <aop:before method="before" pointcut-ref="point"/>
                        <aop:after method="after" pointcut-ref="point"/>
                        <aop:around method="around" pointcut-ref="point"/>
                </aop:aspect>
        </aop:config>

Proxy-target-class= false 默认支持JDK 动态代理方式
Proxy-target-class= true 支持cglib 动态代理方式

jdbcTemplate的使用

​ JdbcTemplate是Spring对JDBC的封装,目的是使JDBC更加易于使用。JdbcTemplate是Spring的一部分。JdbcTemplate处理了资源的建立和释放。
jdbcTemplate可以帮助我们更好的去执行数据库的增删改查工作,具有5种方法:
execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;
update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句;
query方法及queryForXXX方法:用于执行查询相关语句;
call方法:用于执行存储过程、函数相关语句。
接下来实现过程:
导入db.properties,配置druidDataSource数据源,druid也是数据库连接池的一种,dbcp!

    <!--扫描包+注解-->
    <context:component-scan base-package="com.xiaoliu.pojo"/>
    <context:property-placeholder location="db.properties"/>

    <bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
        <property name="driverClassName" value="$jdbc.driverClassName"/>
        <property name="url" value="$jdbc.url"/>
        <property name="password" value="$jdbc.password"/>
        <property name="username" value="$jdbc.name"/>
    </bean>

接下来配置jdbcTemplate

 <bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

dao层类

@Repository
public class UserDao1 
 public  int updata(JdbcTemplate jdbcTemplate)
     String sql = "UPDATE user SET username=?, password=? WHERE id=?;";
     return jdbcTemplate.update(sql,"小牛","123456",123);
 
 public int delete(JdbcTemplate jdbcTemplate)
     String sql = "DELETE FROM user WHERE id=?;";
     return  jdbcTemplate.update(sql,123);
 
 public int insert(JdbcTemplate jdbcTemplate)
     String sql = "INSERT INTO user VALUES (NULL, ?, ?);";
     return jdbcTemplate.update(sql,"小白","123456");
 
public int queryInt(JdbcTemplate jdbcTemplate)
     String sql = "SELECT COUNT(*) FROM user where roleId=1;";
     return jdbcTemplate.queryForObject(sql,Integer.class);



测试:

    ApplicationContext ac =null;
    JdbcTemplate jdbcTemplate = null;
    UserDao1 ud = null;
   @Before
    public void defaultBefore()
         ac = new ClassPathXmlApplicationContext("JDBC.xml");
         jdbcTemplate = (JdbcTemplate) ac.getBean("jdbcTemplate");
         ud = ac.getBean("userDao1", UserDao1.class);
        System.out.println("hello");
    
    @Test
    public void test02()
        System.out.println(ud.updata(jdbcTemplate));
    
    @Test
    public void test03()
        System.out.以上是关于Spring(注解+依赖注入+无配置注解+AOP)适合回顾♥♥的主要内容,如果未能解决你的问题,请参考以下文章

AOP常用注解

spring-bean(注解方式-管理及依赖注入)

Spring从认识到细化了解

框架 day36 Spring3 入门,DI依赖注入,装配bean基于xml/注解, 整合Junit4,配置约束自动提示

Spring之IOC-注解方式

Spring基础知识1--环境搭建bean创建依赖注入注解注入