Spring中的五种设计模式 分析

设计模式在Spring中的运用

  • 单例模式
  1. 概述

单例模式是指类通过使用private的构造函数,确保了在一个应用中只产生一个实例

  1. 单例模式的类图

 

  1. 结构及实现

public class Singleton {

private static final Singleton singleton = new Singleton();

//通过private限制产生多个对象

private Singleton(){ }

//通过该方法获得实例对象

public static Singleton getSingleton(){

return singleton;

}

//类中其他方法,尽量是static

public static void doSomething(){

}

}

  1. Spring中的单例模式

版本:spring-beans-5.1.5.RELEASE.jar

包名:org\springframework\beans\factory\support\

类名:AbstractBeanFactory.class

Spring的主配置文件applicationContext.xml中配置<bean id="productService" class="com.service.productService"

scope="singleton"/> 或者默认配置,Spring才会用单例模式进行创建。

4.1 doGetBean的源码如下:

@SuppressWarnings("unchecked")

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,

@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

 

final String beanName = transformedBeanName(name);

Object bean;

 

// Eagerly check singleton cache for manually registered singletons.

Object sharedInstance = getSingleton(beanName);

if (sharedInstance != null && args == null) {

if (logger.isTraceEnabled()) {

if (isSingletonCurrentlyInCreation(beanName)) {

logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +

"' that is not fully initialized yet - a consequence of a circular reference");

}

else {

logger.trace("Returning cached instance of singleton bean '" + beanName + "'");

}

}

bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);

}

 

else {

// Fail if we're already creating this bean instance:

// We're assumably within a circular reference.

if (isPrototypeCurrentlyInCreation(beanName)) {

throw new BeanCurrentlyInCreationException(beanName);

}

 

// Check if bean definition exists in this factory.

BeanFactory parentBeanFactory = getParentBeanFactory();

if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {

// Not found -> check parent.

String nameToLookup = originalBeanName(name);

if (parentBeanFactory instanceof AbstractBeanFactory) {

return ((AbstractBeanFactory) parentBeanFactory).doGetBean(

nameToLookup, requiredType, args, typeCheckOnly);

}

else if (args != null) {

// Delegation to parent with explicit args.

return (T) parentBeanFactory.getBean(nameToLookup, args);

}

else if (requiredType != null) {

// No args -> delegate to standard getBean method.

return parentBeanFactory.getBean(nameToLookup, requiredType);

}

else {

return (T) parentBeanFactory.getBean(nameToLookup);

}

}

 

if (!typeCheckOnly) {

markBeanAsCreated(beanName);

}

 

try {

final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

checkMergedBeanDefinition(mbd, beanName, args);

 

// Guarantee initialization of beans that the current bean depends on.

String[] dependsOn = mbd.getDependsOn();

if (dependsOn != null) {

for (String dep : dependsOn) {

if (isDependent(beanName, dep)) {

throw new BeanCreationException(mbd.getResourceDescription(), beanName,

"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");

}

registerDependentBean(dep, beanName);

try {

getBean(dep);

}

catch (NoSuchBeanDefinitionException ex) {

throw new BeanCreationException(mbd.getResourceDescription(), beanName,

"'" + beanName + "' depends on missing bean '" + dep + "'", ex);

}

}

}

 

// Create bean instance.

if (mbd.isSingleton()) {

sharedInstance = getSingleton(beanName, () -> {

try {

return createBean(beanName, mbd, args);

}

catch (BeansException ex) {

// Explicitly remove instance from singleton cache: It might have been put there

// eagerly by the creation process, to allow for circular reference resolution.

// Also remove any beans that received a temporary reference to the bean.

destroySingleton(beanName);

throw ex;

}

});

bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

}

 

else if (mbd.isPrototype()) {

// It's a prototype -> create a new instance.

Object prototypeInstance = null;

try {

beforePrototypeCreation(beanName);

prototypeInstance = createBean(beanName, mbd, args);

}

finally {

afterPrototypeCreation(beanName);

}

bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);

}

 

else {

String scopeName = mbd.getScope();

final Scope scope = this.scopes.get(scopeName);

if (scope == null) {

throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");

}

try {

Object scopedInstance = scope.get(beanName, () -> {

beforePrototypeCreation(beanName);

try {

return createBean(beanName, mbd, args);

}

finally {

afterPrototypeCreation(beanName);

}

});

bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);

}

catch (IllegalStateException ex) {

throw new BeanCreationException(beanName,

"Scope '" + scopeName + "' is not active for the current thread; consider " +

"defining a scoped proxy for this bean if you intend to refer to it from a singleton",

ex);

}

}

}

catch (BeansException ex) {

cleanupAfterBeanCreationFailure(beanName);

throw ex;

}

}

 

// Check if required type matches the type of the actual bean instance.

if (requiredType != null && !requiredType.isInstance(bean)) {

try {

T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);

if (convertedBean == null) {

throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());

}

return convertedBean;

}

catch (TypeMismatchException ex) {

if (logger.isTraceEnabled()) {

logger.trace("Failed to convert bean '" + name + "' to required type '" +

ClassUtils.getQualifiedName(requiredType) + "'", ex);

}

throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());

}

}

return (T) bean;

}

4.2 Spring源码的类图

 

4.3 对源码的分析

(1)首先通过final String beanName = transformedBeanName(name);对传入Bean name做处理,防止传入的Bean name名有非法字符(或则做转码) 。

(2)然后取得bean的定义,代码为:final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

(3)再跟据获取的mbd判断xml文件中是否配置的是单例属性

// Create bean instance.

if (mbd.isSingleton()) {

sharedInstance = getSingleton(beanName, () -> {

try {

return createBean(beanName, mbd, args);

}

catch (BeansException ex) {

destroySingleton(beanName);

throw ex;

}

});

bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

}

   如果xml配置的是单例(scope="singleton"),会先通过sharedInstance = getSingleton(beanName)检测单例注册表,然后调用createBean

(beanName, mbd, args);通过所给的beanName创建一个对象bean对象。

当创建的对象向单例注册表注册Bean实例后,会得到最终的bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

在doGetBean方法中的前几行代码中,每次都会首先获得通过final String beanName = transformedBeanName(name),获得beanName,再Object sharedInstance = getSingleton(beanName);检测单例注册表,如果sharedInstance 不为空就会通过bean = getObjectForBeanInstance

(sharedInstance, name, beanName, mbd);得到最终的bean。如果为空则会进一步判断用户是配置的是多例还是单例,或者默认配置。

 

 

 

 

 

 

  • 原型模式
  1. 概述

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

  1. 原型模式的类图

 

  1. 结构及实现

通过clone()方法来实现对象的克隆:

public abstract class AbstractSpoon implements Cloneable

{

String spoonName;

public void setSpoonName(String spoonName) {this.spoonName = spoonName;}

public String getSpoonName() {return this.spoonName;}

public Object clone()

{

Object object = null;

try {

object = super.clone();

} catch (CloneNotSupportedException exception) {

System.err.println("AbstractSpoon is not Cloneable");

}

return object;

}

}

有两个具体实现(ConcretePrototype):

public class SoupSpoon extends AbstractSpoon

{

public SoupSpoon()

{

setSpoonName("Soup Spoon");

}

}

 

  1. Spring中的原型模式

版本:spring-beans-5.1.5.RELEASE.jar

包名:org\springframework\beans\factory\support\

类名:AbstractBeanFactory.class

在Spring中将scope属性值设置为prototype(原型)<bean id="productService" class="com.service.productService" Scope

="prototype"/> Spring就会每次给客户端返回一个新的对象实例

    1.  源码如下:

else if (mbd.isPrototype()) {

// It's a prototype -> create a new instance.

Object prototypeInstance = null;

try {

beforePrototypeCreation(beanName);

prototypeInstance = createBean(beanName, mbd, args);

}

finally {

afterPrototypeCreation(beanName);

}

bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);

}

    1.  Spring源码的类图

 

    1.  对源码的分析

 当判断用户在xml是设置的原型 Scope="prototype"时,在doGetBean中都会调用prototypeInstance = createBean(beanName, mbd, args);方法产生一个实例,创建实例后还会调用afterPrototypeCreation方法判断是否还存在同名的实例,存在就会remove之前的,并add当前创建的,并通过bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);得到一个bean。

 

 

 

 

 

 

 

 

  • 模板模式
  1. 概述

一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行,这种模式就叫做模板模式。

  1. 模板模式的类图

 

  1. 结构及实现

package templateMethod;

public class TemplateMethodPattern

{

    public static void main(String[] args)

    {

        AbstractClass tm=new ConcreteClass();

        tm.TemplateMethod();

    }

}

//抽象类

abstract class AbstractClass

{

    public void TemplateMethod() //模板方法

    {

        SpecificMethod();

        abstractMethod1();          

         abstractMethod2();

    }  

    public void SpecificMethod() //具体方法

    {

        System.out.println("抽象类中的具体方法被调用...");

    }   

    public abstract void abstractMethod1(); //抽象方法1

    public abstract void abstractMethod2(); //抽象方法2

}

//具体子类

class ConcreteClass extends AbstractClass

{

    public void abstractMethod1()

    {

        System.out.println("抽象方法1的实现被调用...");

    }   

    public void abstractMethod2()

    {

        System.out.println("抽象方法2的实现被调用...");

    }

}

  1. Spring 中的模板模式

版本:spring-jdbc-5.1.5.RELEASE.jar

分析的源码主要存在于

org.springframework.jdbc.core.JdbcTemplate.class

org.springframework.jdbc.support.jdbcAccessor.class

org.springframework.jdbc.core.JdbcOperations

    1. 分析jdbcAccessor类

JdbcAccessor是一个抽象类,为子类提供公用属性,主要包括DataSource,SQLExceptionTranslator。

源码:jdbcAccessor中第46、50行

@Nullable

private DataSource dataSource;

@Nullable

private volatile SQLExceptionTranslator exceptionTranslator;

    1. 分析JdbcOperations类

JdbcOperations接口定义了需要JdbcTemplate可以使用的一些操作,如增删改查之类的

源码:(分别列举了第91、113、253、879行)

void execute(String sql) throws DataAccessException;  

<T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException;

int update(String sql) throws DataAccessException;

int update(String sql, Object[] args, int[] argTypes) throws DataAccessException;

    1. 分析JdbcTemplate类

jdbcTemplate类提供了以下方法:

execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;

update方法及batchUpdate方法:update方法用于执行新增、修改、删除等 语句;batchUpdate方法用于执行批处理相关语句;

query方法及queryForXXX方法:用于执行查询相关语句;

call方法:用于执行存储过程、函数相关语句。

    1. JdbcTemplate回调类

ConnectionCallback:通过回调类中doInStatement()方法所提供的数据访问的操作句柄Connection来进行数据访问操作

StatementCallback:同理获得Statement操作句柄来进行操作

PreparedStatementCallback:同理获得PreparedStatement操作句柄进行操作

CallableStatementCallback:主要用于数据库存储过程的访问

  1. 使用ConnectionCallback回调类的源码:第321-341行

@Override

@Nullable

public <T> T execute(ConnectionCallback<T> action) throws DataAccessException {

Assert.notNull(action, "Callback object must not be null");

Connection con = DataSourceUtils.getConnection(obtainDataSource());

try {

// Create close-suppressing Connection proxy, also preparing returned Statements.

Connection conToUse = createConnectionProxy(con);

return action.doInConnection(conToUse);

}

catch (SQLException ex) {

// Release Connection early, to avoid potential connection pool deadlock

// in the case when the exception translator hasn't been initialized yet.

String sql = getSql(action);

DataSourceUtils.releaseConnection(con, getDataSource());

con = null;

throw translateException("ConnectionCallback", sql, ex);

}

finally {

DataSourceUtils.releaseConnection(con, getDataSource());

}

}

  1. 使用StatementCallback回调类的源码:第368-394行

@Override

@Nullable

public <T> T execute(StatementCallback<T> action) throws DataAccessException {

Assert.notNull(action, "Callback object must not be null");

 

Connection con = DataSourceUtils.getConnection(obtainDataSource());

Statement stmt = null;

try {

stmt = con.createStatement();

applyStatementSettings(stmt);

T result = action.doInStatement(stmt);

handleWarnings(stmt);

return result;

}

catch (SQLException ex) {

// Release Connection early, to avoid potential connection pool deadlock

// in the case when the exception translator hasn't been initialized yet.

String sql = getSql(action);

JdbcUtils.closeStatement(stmt);

stmt = null;

DataSourceUtils.releaseConnection(con, getDataSource());

con = null;

throw translateException("StatementCallback", sql, ex);

}

finally {

JdbcUtils.closeStatement(stmt);

DataSourceUtils.releaseConnection(con, getDataSource());

}

}

  1. 使用PreparedStatementCreator 回调类的源码:第600-641行

@Override

@Nullable

public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action)

throws DataAccessException {

Assert.notNull(psc, "PreparedStatementCreator must not be null");

Assert.notNull(action, "Callback object must not be null");

if (logger.isDebugEnabled()) {

String sql = getSql(psc);

logger.debug("Executing prepared SQL statement" + (sql != null ? " [" + sql + "]" : ""));

}

Connection con = DataSourceUtils.getConnection(obtainDataSource());

PreparedStatement ps = null;

try {

ps = psc.createPreparedStatement(con);

applyStatementSettings(ps);

T result = action.doInPreparedStatement(ps);

handleWarnings(ps);

return result;

}

catch (SQLException ex) {

// Release Connection early, to avoid potential connection pool deadlock

// in the case when the exception translator hasn't been initialized yet.

if (psc instanceof ParameterDisposer) {

((ParameterDisposer) psc).cleanupParameters();

}

String sql = getSql(psc);

JdbcUtils.closeStatement(ps);

ps = null;

DataSourceUtils.releaseConnection(con, getDataSource());

con = null;

throw translateException("PreparedStatementCallback", sql, ex);

}

finally {

if (psc instanceof ParameterDisposer) {

((ParameterDisposer) psc).cleanupParameters();

}

JdbcUtils.closeStatement(ps);

DataSourceUtils.releaseConnection(con, getDataSource());

}

}

  1. 使用PreparedStatementCreator 回调类的源码:第600-641行

@Override

@Nullable

public <T> T execute(CallableStatementCreator csc, CallableStatementCallback<T> action)

throws DataAccessException {

Assert.notNull(csc, "CallableStatementCreator must not be null");

Assert.notNull(action, "Callback object must not be null");

if (logger.isDebugEnabled()) {

String sql = getSql(csc);

logger.debug("Calling stored procedure" + (sql != null ? " [" + sql  + "]" : ""));

}

Connection con = DataSourceUtils.getConnection(obtainDataSource());

CallableStatement cs = null;

try {

cs = csc.createCallableStatement(con);

applyStatementSettings(cs);

T result = action.doInCallableStatement(cs);

handleWarnings(cs);

return result;

}

catch (SQLException ex) {

// Release Connection early, to avoid potential connection pool deadlock

// in the case when the exception translator hasn't been initialized yet.

if (csc instanceof ParameterDisposer) {

((ParameterDisposer) csc).cleanupParameters();

}

String sql = getSql(csc);

JdbcUtils.closeStatement(cs);

cs = null;

DataSourceUtils.releaseConnection(con, getDataSource());

con = null;

throw translateException("CallableStatementCallback", sql, ex);

}

finally {

if (csc instanceof ParameterDisposer) {

((ParameterDisposer) csc).cleanupParameters();

}

JdbcUtils.closeStatement(cs);

DataSourceUtils.releaseConnection(con, getDataSource());

}

}

    1. Spring中模板模式的类图

 

 

  • 工厂模式
  1. 概述

工厂模式在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

  1. 工厂模式的代码结构

public abstract class Factory{

    public abstract Sample creator();

    public abstract Sample2 creator(String name);

}

public class SimpleFactory extends Factory{

    public Sample creator(){

        return new SampleA

    }

    public Sample2 creator(String name){

        return new Sample2A

    }

}

public class BombFactory extends Factory{

    public Sample creator(){

        return new SampleB

    }

    public Sample2 creator(String name){

        return new Sample2B

    }

}

 

 

  1. 工厂模式的类图

 

  1. Spring中的工厂模式

Spring中的工厂模式主要体现在BeanFactory和ApplicationContext,BeanFactory创建bean会延迟注入,用到某个bean时才会注入创建,节约内存。ApplicationContext是容器启动的时候,一次性创建所有 bean,但application也扩展了A BeanFactory。

4.1 Spring中的工厂模式源码

版本:spring-beans-5.1.5.RELEASE.jar

包名:\org\springframework\beans

类名:FactoryBean、SmartFactoryBean、AbstractFactoryBean

/*

* Copyright 2002-2018 the original author or authors.

*

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

*      http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/

package org.springframework.beans.factory;

import org.springframework.lang.Nullable;

/**

* Interface to be implemented by objects used within a {@link BeanFactory} which

* are themselves factories for individual objects. If a bean implements this

* interface, it is used as a factory for an object to expose, not directly as a

* bean instance that will be exposed itself.

*

* <p><b>NB: A bean that implements this interface cannot be used as a normal bean.</b>

* A FactoryBean is defined in a bean style, but the object exposed for bean

* references ({@link #getObject()}) is always the object that it creates.

*

* <p>FactoryBeans can support singletons and prototypes, and can either create

* objects lazily on demand or eagerly on startup. The {@link SmartFactoryBean}

* interface allows for exposing more fine-grained behavioral metadata.

*

* <p>This interface is heavily used within the framework itself, for example for

* the AOP {@link org.springframework.aop.framework.ProxyFactoryBean} or the

* {@link org.springframework.jndi.JndiObjectFactoryBean}. It can be used for

* custom components as well; however, this is only common for infrastructure code.

*

* <p><b>{@code FactoryBean} is a programmatic contract. Implementations are not

* supposed to rely on annotation-driven injection or other reflective facilities.</b>

* {@link #getObjectType()} {@link #getObject()} invocations may arrive early in

* the bootstrap process, even ahead of any post-processor setup. If you need access

* other beans, implement {@link BeanFactoryAware} and obtain them programmatically.

*

* <p>Finally, FactoryBean objects participate in the containing BeanFactory's

* synchronization of bean creation. There is usually no need for internal

* synchronization other than for purposes of lazy initialization within the

* FactoryBean itself (or the like).

*

* @author Rod Johnson

* @author Juergen Hoeller

* @since 08.03.2003

* @param <T> the bean type

* @see org.springframework.beans.factory.BeanFactory

* @see org.springframework.aop.framework.ProxyFactoryBean

* @see org.springframework.jndi.JndiObjectFactoryBean

*/

public interface FactoryBean<T> {

/**

* Return an instance (possibly shared or independent) of the object

* managed by this factory.

* <p>As with a {@link BeanFactory}, this allows support for both the

* Singleton and Prototype design pattern.

* <p>If this FactoryBean is not fully initialized yet at the time of

* the call (for example because it is involved in a circular reference),

* throw a corresponding {@link FactoryBeanNotInitializedException}.

* <p>As of Spring 2.0, FactoryBeans are allowed to return {@code null}

* objects. The factory will consider this as normal value to be used; it

* will not throw a FactoryBeanNotInitializedException in this case anymore.

* FactoryBean implementations are encouraged to throw

* FactoryBeanNotInitializedException themselves now, as appropriate.

* @return an instance of the bean (can be {@code null})

* @throws Exception in case of creation errors

* @see FactoryBeanNotInitializedException

*/

@Nullable

T getObject() throws Exception;

/**

* Return the type of object that this FactoryBean creates,

* or {@code null} if not known in advance.

* <p>This allows one to check for specific types of beans without

* instantiating objects, for example on autowiring.

* <p>In the case of implementations that are creating a singleton object,

* this method should try to avoid singleton creation as far as possible;

* it should rather estimate the type in advance.

* For prototypes, returning a meaningful type here is advisable too.

* <p>This method can be called <i>before</i> this FactoryBean has

* been fully initialized. It must not rely on state created during

* initialization; of course, it can still use such state if available.

* <p><b>NOTE:</b> Autowiring will simply ignore FactoryBeans that return

* {@code null} here. Therefore it is highly recommended to implement

* this method properly, using the current state of the FactoryBean.

* @return the type of object that this FactoryBean creates,

* or {@code null} if not known at the time of the call

* @see ListableBeanFactory#getBeansOfType

*/

@Nullable

Class<?> getObjectType();

 

/**

* Is the object managed by this factory a singleton? That is,

* will {@link #getObject()} always return the same object

* (a reference that can be cached)?

* <p><b>NOTE:</b> If a FactoryBean indicates to hold a singleton object,

* the object returned from {@code getObject()} might get cached

* by the owning BeanFactory. Hence, do not return {@code true}

* unless the FactoryBean always exposes the same reference.

* <p>The singleton status of the FactoryBean itself will generally

* be provided by the owning BeanFactory; usually, it has to be

* defined as singleton there.

* <p><b>NOTE:</b> This method returning {@code false} does not

* necessarily indicate that returned objects are independent instances.

* An implementation of the extended {@link SmartFactoryBean} interface

* may explicitly indicate independent instances through its

* {@link SmartFactoryBean#isPrototype()} method. Plain {@link FactoryBean}

* implementations which do not implement this extended interface are

* simply assumed to always return independent instances if the

* {@code isSingleton()} implementation returns {@code false}.

* <p>The default implementation returns {@code true}, since a

* {@code FactoryBean} typically manages a singleton instance.

* @return whether the exposed object is a singleton

* @see #getObject()

* @see SmartFactoryBean#isPrototype()

*/

default boolean isSingleton() {

return true;

}

}

4.2 Spring中的工厂模式类图

 

  • 代理模式
  1. 概述

代理模式指一个类别可以作为其它东西的接口。某个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用

代理模式分为:静态代理、动态代理、CGLIB代理

  1. 代理模式的代码结构

 

  1. Spring中的代理模式

AOP的实现原理是动态代理技术目前动态代理技术主要分为Java自己提供的JDK动态代理技术和CGLIB技术。Java自带的JDK动态代理技术是需要接口的,而CGLIB则是直接修改字节码Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib ,这时候Spring AOP会使用 Cglib 生成一个被代理对象的子类来作为代理

 

3.1 Spring中的代理模式源码

版本:spring-aop-5.1.5.RELEASE.jar

包名:\org\springframework\aop\framework

类名:AopProxy.class、CglibAopProxy、JdkDynamicAopProxy

源码:

 

/*

 * Copyright 2002-2018 the original author or authors.

 *

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *      http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */

 

package org.springframework.aop.framework;

 

import java.io.Serializable;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

import java.util.List;

 

import org.aopalliance.intercept.MethodInvocation;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

 

import org.springframework.aop.AopInvocationException;

import org.springframework.aop.RawTargetAccess;

import org.springframework.aop.TargetSource;

import org.springframework.aop.support.AopUtils;

import org.springframework.core.DecoratingProxy;

import org.springframework.lang.Nullable;

import org.springframework.util.Assert;

import org.springframework.util.ClassUtils;

 

/**

 * JDK-based {@link AopProxy} implementation for the Spring AOP framework,

 * based on JDK {@link java.lang.reflect.Proxy dynamic proxies}.

 *

 * <p>Creates a dynamic proxy, implementing the interfaces exposed by

 * the AopProxy. Dynamic proxies <i>cannot</i> be used to proxy methods

 * defined in classes, rather than interfaces.

 *

 * <p>Objects of this type should be obtained through proxy factories,

 * configured by an {@link AdvisedSupport} class. This class is internal

 * to Spring's AOP framework and need not be used directly by client code.

 *

 * <p>Proxies created using this class will be thread-safe if the

 * underlying (target) class is thread-safe.

 *

 * <p>Proxies are serializable so long as all Advisors (including Advices

 * and Pointcuts) and the TargetSource are serializable.

 *

 * @author Rod Johnson

 * @author Juergen Hoeller

 * @author Rob Harrop

 * @author Dave Syer

 * @see java.lang.reflect.Proxy

 * @see AdvisedSupport

 * @see ProxyFactory

 */

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

 

/** use serialVersionUID from Spring 1.2 for interoperability. */

private static final long serialVersionUID = 5531744639992436476L;

 

 

/*

 * NOTE: We could avoid the code duplication between this class and the CGLIB

 * proxies by refactoring "invoke" into a template method. However, this approach

 * adds at least 10% performance overhead versus a copy-paste solution, so we sacrifice

 * elegance for performance. (We have a good test suite to ensure that the different

 * proxies behave the same :-)

 * This way, we can also more easily take advantage of minor optimizations in each class.

 */

 

/** We use a static Log to avoid serialization issues. */

private static final Log logger = LogFactory.getLog(JdkDynamicAopProxy.class);

 

/** Config used to configure this proxy. */

private final AdvisedSupport advised;

 

/**

 * Is the {@link #equals} method defined on the proxied interfaces?

 */

private boolean equalsDefined;

 

/**

 * Is the {@link #hashCode} method defined on the proxied interfaces?

 */

private boolean hashCodeDefined;

 

 

/**

 * Construct a new JdkDynamicAopProxy for the given AOP configuration.

 * @param config the AOP configuration as AdvisedSupport object

 * @throws AopConfigException if the config is invalid. We try to throw an informative

 * exception in this case, rather than let a mysterious failure happen later.

 */

public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {

Assert.notNull(config, "AdvisedSupport must not be null");

if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {

throw new AopConfigException("No advisors and no TargetSource specified");

}

this.advised = config;

}

 

 

@Override

public Object getProxy() {

return getProxy(ClassUtils.getDefaultClassLoader());

}

 

@Override

public Object getProxy(@Nullable ClassLoader classLoader) {

if (logger.isTraceEnabled()) {

logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());

}

Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);

findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);

return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

}

 

/**

 * Finds any {@link #equals} or {@link #hashCode} method that may be defined

 * on the supplied set of interfaces.

 * @param proxiedInterfaces the interfaces to introspect

 */

private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {

for (Class<?> proxiedInterface : proxiedInterfaces) {

Method[] methods = proxiedInterface.getDeclaredMethods();

for (Method method : methods) {

if (AopUtils.isEqualsMethod(method)) {

this.equalsDefined = true;

}

if (AopUtils.isHashCodeMethod(method)) {

this.hashCodeDefined = true;

}

if (this.equalsDefined && this.hashCodeDefined) {

return;

}

}

}

}

 

 

/**

 * Implementation of {@code InvocationHandler.invoke}.

 * <p>Callers will see exactly the exception thrown by the target,

 * unless a hook method throws an exception.

 */

@Override

@Nullable

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

MethodInvocation invocation;

Object oldProxy = null;

boolean setProxyContext = false;

 

TargetSource targetSource = this.advised.targetSource;

Object target = null;

 

try {

if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {

// The target does not implement the equals(Object) method itself.

return equals(args[0]);

}

else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {

// The target does not implement the hashCode() method itself.

return hashCode();

}

else if (method.getDeclaringClass() == DecoratingProxy.class) {

// There is only getDecoratedClass() declared -> dispatch to proxy config.

return AopProxyUtils.ultimateTargetClass(this.advised);

}

else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&

method.getDeclaringClass().isAssignableFrom(Advised.class)) {

// Service invocations on ProxyConfig with the proxy config...

return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);

}

 

Object retVal;

 

if (this.advised.exposeProxy) {

// Make invocation available if necessary.

oldProxy = AopContext.setCurrentProxy(proxy);

setProxyContext = true;

}

 

// Get as late as possible to minimize the time we "own" the target,

// in case it comes from a pool.

target = targetSource.getTarget();

Class<?> targetClass = (target != null ? target.getClass() : null);

 

// Get the interception chain for this method.

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

 

// Check whether we have any advice. If we don't, we can fallback on direct

// reflective invocation of the target, and avoid creating a MethodInvocation.

if (chain.isEmpty()) {

// We can skip creating a MethodInvocation: just invoke the target directly

// Note that the final invoker must be an InvokerInterceptor so we know it does

// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.

Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);

retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);

}

else {

// We need to create a method invocation...

invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);

// Proceed to the joinpoint through the interceptor chain.

retVal = invocation.proceed();

}

 

// Massage return value if necessary.

Class<?> returnType = method.getReturnType();

if (retVal != null && retVal == target &&

returnType != Object.class && returnType.isInstance(proxy) &&

!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {

// Special case: it returned "this" and the return type of the method

// is type-compatible. Note that we can't help if the target sets

// a reference to itself in another returned object.

retVal = proxy;

}

else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {

throw new AopInvocationException(

"Null return value from advice does not match primitive return type for: " + method);

}

return retVal;

}

finally {

if (target != null && !targetSource.isStatic()) {

// Must have come from TargetSource.

targetSource.releaseTarget(target);

}

if (setProxyContext) {

// Restore old proxy.

AopContext.setCurrentProxy(oldProxy);

}

}

}

/**

 * Equality means interfaces, advisors and TargetSource are equal.

 * <p>The compared object may be a JdkDynamicAopProxy instance itself

 * or a dynamic proxy wrapping a JdkDynamicAopProxy instance.

 */

@Override

public boolean equals(@Nullable Object other) {

if (other == this) {

return true;

}

if (other == null) {

return false;

}

 

JdkDynamicAopProxy otherProxy;

if (other instanceof JdkDynamicAopProxy) {

otherProxy = (JdkDynamicAopProxy) other;

}

else if (Proxy.isProxyClass(other.getClass())) {

InvocationHandler ih = Proxy.getInvocationHandler(other);

if (!(ih instanceof JdkDynamicAopProxy)) {

return false;

}

otherProxy = (JdkDynamicAopProxy) ih;

}

else {

// Not a valid comparison...

return false;

}

 

// If we get here, otherProxy is the other AopProxy.

return AopProxyUtils.equalsInProxy(this.advised, otherProxy.advised);

}

 

/**

 * Proxy uses the hash code of the TargetSource.

 */

@Override

public int hashCode() {

return JdkDynamicAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode();

}

 

}

 

3.2 Spring中的代理模式类图

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值