There are a few good documents available to gain understanding on what these two aspects do:
I believe extension attributes are preferred when adding custom data to entities such as an order. This is because M2 introduces services contracts (interfaces). These service contracts define the available getters and setters for an entity (such as
setDescription() etc). We cannot change the service contract to add new getters and setters every time we want to add custom data to an entity, therefore we set custom data via the extension attributes.
In regards to
getCustomAttributes(), I believe this is just used to retrieve any non-standard EAV attributes for entities such as products. To quote the dev docs:
The Catalog module has several attributes that are defined as EAV
attributes, but are treated as built-in attributes. These attributes
In this case, when getCustomAttributes() is called, the system returns
only custom attributes that are not in this list.
For example, if you have a custom product attribute named
custom_message, this may not be immediately available on a product model - however it will be available once calling
As I said, the links I provided explain the two features in a bit more depth.
Hope this helps :)